15
5 Ways to Write DML Triggers That Don’t Suck Aaron Bertrand SQL Sentry [email protected]

5 Ways to Write DML Triggers That Don’t Suck

  • Upload
    landen

  • View
    27

  • Download
    0

Embed Size (px)

DESCRIPTION

5 Ways to Write DML Triggers That Don’t Suck. Aaron Bertrand SQL Sentry [email protected]. About Me. Aaron Bertrand Senior Consultant @ AaronBertrand Microsoft MVP since 1997 Author, MVP Deep Dives 1 & 2 http://sqlblog.com/ http://sqlperformance.com/ - PowerPoint PPT Presentation

Citation preview

Page 1: 5 Ways to Write DML Triggers That Don’t Suck

5 Ways to Write DML Triggers That Don’t Suck

Aaron BertrandSQL Sentry

[email protected]

Page 2: 5 Ways to Write DML Triggers That Don’t Suck

2© SQLintersection. All rights reserved.

http://www.SQLintersection.com

About Me

Aaron Bertrand Senior Consultant @AaronBertrand

Microsoft MVP since 1997Author, MVP Deep Dives 1 & 2http://sqlblog.com/http://sqlperformance.com/[email protected]

http://sqlsentry.com/

Page 3: 5 Ways to Write DML Triggers That Don’t Suck

3© SQLintersection. All rights reserved.

http://www.SQLintersection.com

Agenda

What are triggers? Why do we use triggers? How do triggers work? Triggers can affect more than one row Triggers need to be as quick as possible Avoid UPDATE() and COLUMNS_UPDATED() MERGE has funny effects on triggers INSTEAD OF triggers Measure trigger performance A few other tips Other alternatives

Page 4: 5 Ways to Write DML Triggers That Don’t Suck

4© SQLintersection. All rights reserved.

http://www.SQLintersection.com

What are triggers?

We’ll talk about DML triggers today There are also DDL triggers and logon triggers

Piece of code that runs in response to some DML action INSERT, UPDATE, DELETE, MERGE

Page 5: 5 Ways to Write DML Triggers That Don’t Suck

5© SQLintersection. All rights reserved.

http://www.SQLintersection.com

Why do we use triggers?

Variety of purposes Enforcing business logic

Rolling back violations not easily caught by constraints

Facilitating foreign keys FKs can’t span databases or servers FKs can cycle or have multiple paths, eliminating CASCADE options

Auditing Tracking changes, logging activity, sending e-mail, updating

LastModified

Maintaining peripheral data Updating rank column, adjusting aggregates

INSTEAD OF triggers on views

Page 6: 5 Ways to Write DML Triggers That Don’t Suck

6© SQLintersection. All rights reserved.

http://www.SQLintersection.com

How do triggers work?

inserted & deleted pseudo-tables contain *all* affected rows

inserted contains new version of row deleted contains old version of row Both are populated on update

Pseudo-tables use version store

Even if you don’t enable snapshot This means triggers can contribute to tempdb contention

Much improved mechanism Used to read the transaction log backwards to reconstruct

affected rows

Page 7: 5 Ways to Write DML Triggers That Don’t Suck

7© SQLintersection. All rights reserved.

http://www.SQLintersection.com

Triggers aren’t single row

SQL Server fires triggers *per action* not *per row*

Don’t store “the row” in variables

Don’t “fix” that by implementing a loop or cursor You are always operating on a set – treat this like one, too

Page 8: 5 Ways to Write DML Triggers That Don’t Suck

8© SQLintersection. All rights reserved.

http://www.SQLintersection.com

Get In, Get Out

Triggers – when necessary – need to be quick

Avoid any reliance on external resources Sending mail, writing to log files, xp_cmdshell, CLR Use Service Broker or optimized queue tables to perform additional

work Database Mail is ok, but I still prefer a queue table – more control

Optimize code paths Test the plans for the operations in your trigger Avoid involving tables with high contention / concurrency Use short circuit operations like EXISTS when possible And again, avoid cursors or loops

Page 9: 5 Ways to Write DML Triggers That Don’t Suck

9© SQLintersection. All rights reserved.

http://www.SQLintersection.com

Avoid UPDATE() / COLUMNS_UPDATED()

Not very useful to know when values have actually changed Or which specific rows had values that actually changed

Useful only to know what columns are referenced in the UPDATE

Page 10: 5 Ways to Write DML Triggers That Don’t Suck

10© SQLintersection. All rights reserved.

http://www.SQLintersection.com

Test trigger logic with MERGE

Trigger fires once per DML action, not once per MERGE statement Things like @@ROWCOUNT are unreliable

Please MERGE with caution anyway:

http://bit.ly/merge-with-caution

Page 11: 5 Ways to Write DML Triggers That Don’t Suck

11© SQLintersection. All rights reserved.

http://www.SQLintersection.com

Use INSTEAD OF Triggers

Can be more efficient to prevent than to do and then undo Particularly if it is a log-heavy operation

No free lunch, though You have to re-write the DML statement to pull from

inserted/deleted Worktable instead of version store

Page 12: 5 Ways to Write DML Triggers That Don’t Suck

12© SQLintersection. All rights reserved.

http://www.SQLintersection.com

Measure trigger performance

sys.dm_exec_trigger_stats Get max / min / avg / last reads, writes and durations for every

trigger

However: Not persisted through actions like service restarts

SELECT [trigger] = tr.name, tr.is_instead_of_trigger, [table] = s.name + '.' + o.name, last_execution_time, execution_count, max_elapsed_time, max_logical_reads, avg_elapsed_time = ts.total_elapsed_time*1.0/execution_count FROM sys.dm_exec_trigger_stats AS ts INNER JOIN sys.triggers AS tr ON ts.[object_id] = tr.[object_id] INNER JOIN sys.objects AS o ON tr.parent_id = o.[object_id] INNER JOIN sys.schemas AS s ON o.[schema_id] = s.[schema_id] WHERE ts.database_id = DB_ID() AND ts.[type] = N'TR' AND tr.is_disabled = 0;

Page 13: 5 Ways to Write DML Triggers That Don’t Suck

13© SQLintersection. All rights reserved.

http://www.SQLintersection.com

A few other tips

Be very careful about nested triggers (Trigger writes to table that has its own triggers)

Always use SCOPE_IDENTITY() or OUTPUT, not @@IDENTITY (Trigger could write to a table that has its own IDENTITY column)

Check if a trigger exists on a table before you add another one If you do need multiple triggers, use sp_settriggerorder

If you perform multiple operations, put ones most likely to fail first

If work may rollback, don’t waste effort

Use source control, since triggers are less discoverable

Page 14: 5 Ways to Write DML Triggers That Don’t Suck

14© SQLintersection. All rights reserved.

http://www.SQLintersection.com

Don’t write triggers at all

Don't use triggers when you don't need them For example: INSERT trigger that updates CreatedDate – use a

default!

Alternatives: Default / check constraints Computed columns

Choose when to take the hit: PERSISTED Indexed views Change Data Capture / Change Tracking / Auditing Perform logic in app/procedures

(Restrict all data access to stored procedures)

Page 15: 5 Ways to Write DML Triggers That Don’t Suck

15© SQLintersection. All rights reserved.

http://www.SQLintersection.com

THANK YOU!