{"id":73171,"date":"2015-03-16T16:03:52","date_gmt":"2015-03-16T16:03:52","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/uncategorized\/the-problem-with-triggers\/"},"modified":"2021-07-14T13:07:26","modified_gmt":"2021-07-14T13:07:26","slug":"the-problem-with-triggers","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/databases\/oracle-databases\/the-problem-with-triggers\/","title":{"rendered":"The Problem With Triggers"},"content":{"rendered":"<p>Feeling brave?\u00a0 Enjoy danger? Well, I dare you to walk into a room full of Oracle experts wearing an <b><i>I <\/i><\/b><i>\u2665 <b>DATABASE TRIGGERS<\/b> <\/i>t-shirt. Let\u2019s see if you walk out of that room alive.<\/p>\n<p>Database triggers are the Oracle feature that developers love to hate, perhaps above every other.\u00a0 And it\u2019s pretty unanimous \u2013 from luminaries like Tom \u201cTriggers are evil\u201d Kyte \u00a0to people like <a href=\"https:\/\/www.red-gate.com\/simple-talk\/author\/david-njoku\/\" target=\"_blank\" rel=\"noopener\">this dude<\/a> (\u201cTriggers are powerful \u2013 and much despised\u201d).<\/p>\n<h3>The Problem with Triggers<\/h3>\n<p>But, you may be wondering, why are triggers so hated? What\u2019s the big deal? You understand them; you know what you\u2019re doing.<\/p>\n<p>To answer your question, let me start by quoting myself again:<\/p>\n<blockquote>\n<p><i>Simple triggers to populate primary key columns from sequences are pretty uncontroversial; however, there is no upper limit to their potential complexity.\u00a0 They can be hundreds of lines long and contain convoluted conditions.\u00a0 Many developers dislike them because they fire silently in the background, seeming to live just beyond the fingertips of their control.<\/i><\/p>\n<\/blockquote>\n<h3>Uncontrolled Processes<\/h3>\n<p>The issue I was highlighting is that because triggers fire automatically, they can sometimes seem like hidden anarchists lobbing Molotov cocktails into your code from the shadows. Imagine you have a huge table \u2013 1 million rows \u2013 and you need to update a column. It\u2019s a huge task, but your table is properly indexed so you\u2019re not too worried. Maybe it\u2019ll take a few minutes.<\/p>\n<p>Two hours later you\u2019re sitting there scratching your head. And that\u2019s when you remember that your table has a <i>for each row<\/i> after-update trigger that inserts into an audit table, synchronises a mirror table, performs some calculations, updates some other columns, and, probably, pauses to smoke a cigar too. Triggers are evil.<\/p>\n<p>Triggers lie too. Imagine you write a simple statement to update 10 records and run it. <i>10 rows processed<\/i>, the message says. Oh really? If you have triggers on the table, not even Nostradamus knows how many records across the database were really updated. Triggers are evil.<\/p>\n<h3>Maintenance Nightmare<\/h3>\n<p>Triggers are also a convenient hiding place for bugs. When your code errors, it is natural to go over the code you have just written looking for fractures in the logic; no one ever remembers to look in the triggers that may be firing in silence. Triggers are evil.<\/p>\n<p>In fact, in researching this article, I learned that I was wrong when I wrote that <i>simple triggers to populate primary key columns from sequences are pretty uncontroversial.<\/i> Many developers refuse to tolerate even that. They recommend that you build APIs to interact with your tables, and populate your primary key columns that way.\u00a0 No need for a trigger. I can\u2019t argue with that.<\/p>\n<h3>Rollback Problems<\/h3>\n<p>Tom Kyte points out another reason to be wary of triggers. Imagine you maintain a database for a business that sends a \u00a35 discount code to every customer who makes a purchase. To implement it you write an after-insert trigger on the SALES table. For each row inserted into SALES, the trigger makes a call to utl_mail.send to automatically send an email containing the discount code to the customer.<\/p>\n<p>Whatever could go wrong?<\/p>\n<p>Rollback.<\/p>\n<p>If, for whatever reason, your transaction is rolled back after you\u2019ve inserted 100 rows into SALES, those rows will be erased \u2013 but what about the emails? Sent. Gone. The customers are probably blowing your cash right now. Ouch. Triggers are evil.<\/p>\n<p>And it\u2019s not just utl_mail; the same thing would happen with utl_file, utl_http, and many other utl_ functions.<\/p>\n<p>And it is a popular practice to write audit records using autonomous transactions fired from within triggers.\u00a0 Same issue. If your main process is rolled back, you\u2019ll be left with your audit records. Like the footprints of a ghost.<\/p>\n<h3>What Are Triggers Good For?<\/h3>\n<p>At this point you\u2019re probably asking the sensible question: if triggers are evil, why do they exist? It\u2019s almost as if they\u2019re the apple tree in the middle of Eden, a trap placed there to tempt us to sin.<\/p>\n<p>Not exactly.<\/p>\n<p>I use them to maintain modified by and modified date columns.\u00a0 And yes, I still use them to populate primary key columns that depend on sequences. Sue me.<\/p>\n<p>And, despite highlighting the danger of using them for auditing, we do still maintain some legacy code that does that. If I was starting today, I would definitely use fine grained auditing instead, but we can\u2019t rewrite the past, at least not cheaply.<\/p>\n<p>Some developers use triggers to implement complex check constraints, since ordinary check constraints cannot reference other tables or include things like sub-queries. You can build a trigger that will carry out your checks before an update or insert and rebuff the transaction if it fails.<\/p>\n<p>Fair enough. But if you build transactional APIs and use them strictly, you can include your complex check in your API and not need a trigger.<\/p>\n<h3>When Should You Use Triggers?<\/h3>\n<p>Never. THE END.<\/p>\n<p>Oh, is that answer too short for you? Need something longer? Yes, I confess that the main database I work with still has a number of triggers in it, and I know that that makes me sound hypocritical. But it is 15 years old, and sometimes it\u2019s too much trouble to erase the fingerprints of past developers.<\/p>\n<p>But if you do not have that problem, do not use triggers \u2013 unless they are the only solution to your particular problem.<\/p>\n<p>And if you think they are the only solution to your particular problem, think again. You\u2019re probably wrong. Believe me.<\/p>\n<p>So that\u2019s it, triggers.\u00a0 Now, we\u2019re all on the same page. We all agree: trigger-happy is a dirty word. So take off that <b><i>I <\/i><\/b><i>\u2665 <b>DATABASE TRIGGERS<\/b> <\/i>t-shirt; let\u2019s set fire to it.<\/p>\n<p><em>References:<\/em><\/p>\n<p><a href=\"https:\/\/allthingsoracle.com\/oracle-for-absolute-beginners-part-7-creating-tables-constraints-and-triggers\/\">https:\/\/allthingsoracle.com\/oracle-for-absolute-beginners-part-7-creating-tables-constraints-and-triggers\/<\/a><\/p>\n<p><a href=\"http:\/\/www.oracle.com\/technetwork\/testcontent\/o58asktom-101055.html\" target=\"_blank\" rel=\"noopener\">http:\/\/www.oracle.com\/technetwork\/testcontent\/o58asktom-101055.html<\/a><\/p>\n<p><a href=\"http:\/\/tkyte.blogspot.co.uk\/2010\/04\/that-old-restart-problem-again.html\" target=\"_blank\" rel=\"noopener\">http:\/\/tkyte.blogspot.co.uk\/2010\/04\/that-old-restart-problem-again.html<\/a><\/p>\n<p><a href=\"http:\/\/it.toolbox.com\/blogs\/oracle-guide\/when-to-use-triggers-and-when-not-to-24837\" target=\"_blank\" rel=\"noopener\">http:\/\/it.toolbox.com\/blogs\/oracle-guide\/when-to-use-triggers-and-when-not-to-24837<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Feeling brave?\u00a0 Enjoy danger? Well, I dare you to walk into a room full of Oracle experts wearing an I \u2665 DATABASE TRIGGERS t-shirt. Let&#8217;s see if you walk out of that room alive. Database triggers are the Oracle feature that developers love to hate, perhaps above every other.\u00a0&hellip;<\/p>\n","protected":false},"author":221907,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143533],"tags":[5149,48529],"coauthors":[48557],"class_list":["post-73171","post","type-post","status-publish","format-standard","hentry","category-oracle-databases","tag-advice","tag-triggers"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/73171","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221907"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=73171"}],"version-history":[{"count":2,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/73171\/revisions"}],"predecessor-version":[{"id":75221,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/73171\/revisions\/75221"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=73171"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=73171"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=73171"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=73171"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}