This month’s invite comes once again from our
benevolent overlord* community pillar Steve Jones, head of SQLServerCentral.com! If you haven’t been there, stop reading immediately and go check out the helpful forums and ‘Stairways’ articles. Some truly excellent content to be had.
No, don’t stop reading immediately… save it to your favorites/reading-list and look at it in 5 minutes when you’re done here. =)
*Though I’ve not had the pleasure of meeting him in person, I’ve heard Steve is a phenomenally humble and down-to-earth guy, so my silly comment about him is even sillier in that light. ❤
Triggers – Love ’em or Hate ’em
Borrowing a bit of a mini-game from the CodingBlocks guys, the first “Google-feud” (auto-complete result) for “sql server triggers are ” is
sql server are triggers bad. Well, they can be, if used improperly / to excess. Like most bits of tech, they have their place and their use-cases.
I’ve blogged about a few such use-cases here (a “who did what” audit-trail type of trigger) and here (as part of the Nested Set Model implementation), which you should definitely read. I didn’t condone click-baity titles back then. Alas…
Here are handful of anti-patterns that I’ve seen with triggers in my time.
Thing 1: Using them as Queues
Repeat after me:
A trigger is not a queue.
Triggers are executed within the same transaction as the query that fires them. Meaning, they’re subject to all that
ACID-y goodness of a transactional system. This is a double-edged sword. If all is successful, it guarantees that trigger will do its job when the calling query runs, which is great for audit-ability. On the other hand, if the trigger has a problem, anything and everything that
triggers it will also fail.
The fundamental distinction between this and a queue, is that the success of the queued action is not immediately critical to the continued operation of the thing that called (queued) it.
So if your requirement matches the latter behavior, and not the former, do us all a favor and use a real queue. Heck, find one of the few people who know Service Broker. (Hint: one’s a Warewolf, another’s a Poolboy.)
Thing 2: Making them WAY TOO BIG
Mostly because of the transactional thing, the rule of thumb with triggers is K.I.S.S. “Keep it Small and Simple.” Even the audit-trail example is a bit much if the table being audited is under significant write load. Typically, if the business requirements are both high-throughput and high audit-ability, you’ll be implementing a much more complicated tech-stack than just plain ol’ SQL Server with triggers.
Some of the offenders I’ve seen include: A trigger that wanted to write to several other tables with
IF conditions that branched based on what column was being updated. And a trigger that required near-
SA level permissions to do some back-end maintenance-y stuff. Those are both recipes for problem pie.
Thing 3: Doing Nothing Useful
Somewhat opposite of above, there’s no point in introducing the management and performance overhead of triggers if they’re not performing a transaction-critical operation. For instance, something better left to a queue.
Thing 4: Housing Business Logic
There’s always been a holy war about whether “business logic” belongs in the database or in the application code. And, since geeks love sub-classifying things to the Nth degree, there’s a sub-holy-war about what “business logic” actually means. But I won’t go into that here.
If you fall on the 1st side of the fence, and you feel the desperate desire to embed some logic in the data layer, it belongs in
stored procedures, not in triggers. Reasons include maintaintability, discoverability, performance, documentability. Not to mention source-control on
procs is a helluva lot easier than on triggers.
Thing 5: Too Many of Them
While multiple triggers can be defined for the same action on the same table, that’s not an invitation. You enforce trigger execution order to an extent (first and last), but any more than that and you’re asking for confusion. Falling back on the KISS principle, if you need more than one trigger on a table & action (
delete), you probably need to rethink the underlying design.
INSTEAD OF vs.
AFTER: it’s fairly self-explanatory, but just be aware of what you’re doing, especially with the former. You’re literally replacing the desired action of, say, an
update query with the contents of your
instead of update trigger. If this is not obvious to all users of this table, you’re in for some really surprised faces and angry messages.
And that’s all I have for today folks! Enjoy
triggering stuff. In moderation, as all things. =)