T-SQL and transaction flow - from first to last

2019-02-16 04:18发布

问题:

Let's say I have table TabA with columns:

  • col1 - primary key (but not identity)

  • col2 - foreign key

  • col3 - with unique constraint

  • col4 - with check constraint

  • col5 - with NOT NULL constraint

Also, TabA has 2 triggers:

  • INSTEAD OF INSERT - this one cancel insert into TabA (of course), but in it's own code insert new row into TabA. The values for all column in this new row are guaranteed correct

  • AFTER INSERT - this one just print string

Now, I am ready insert new row into TabA (INSERT INTO TabA VALUES(...)). Obviously, we have to expect some events:

  1. value for col1 must be checked for uniqueness and NOT NULL(primary key)

  2. value for col2 must be checked for conformity to the parental table(foreign key)

  3. value for col3 must be checked for uniqueness

  4. value for col4 must be checked against check constraint

  5. value for col5 must be checked for NOT NULL

  6. INSTEAD OF trigger must be executed

  7. AFTER trigger must be executed

What I want is reorder this list(1-7) so that number 1 be on event that will happen first, 2=event that will happen second, ..., and 7 for the last event.

Also, if event X produce error (col5=NULL, for example) - does this mean that events X+1,X+2.. will NOT happen?

Thanks for you help!

回答1:

This is easy to test by setting up test tables as described with print statements in the triggers and simply trying to insert invalid values. Doing so gave for me

  1. Instead Of Trigger
  2. Checks NULL of PK
  3. Checks NULL of column 5
  4. Checks uniqueness of PK constraint
  5. Checks uniqueness of unique constraint
  6. Checks check constraint of column 4
  7. Checks FK constraint
  8. Fires After Trigger

As far as I know the order of 1,7, and 8 are guaranteed. The rest are arbitrary. Any error will stop succeeding steps.



回答2:

General order of execution for INSERT, UPDATE, DELETE statements:

  • Enforce all table- and row-level constraints. Note that you have zero control over the order in which these constraints are checked.
  • If an INSTEAD OF trigger exists for the statement being executed, execute it.
  • Execute all apropriate AFTER triggers, in undefined order, with the following exceptions:
    • IF an after trigger has been specified as the first or last to be executed via sp_settriggerorder, execute those at the appropriate point, with any remaining triggers executed in undefined order.

You may have only 1 INSTEAD OF trigger (per action: INSERT, UPDATE or DELETE). That trigger will always get executed before any AFTER triggers, since it executes in lieue of the corresponding INSERT, UPDATE or DELETE statement.

AFTER triggers are always executed, oddly enough, AFTER the data modification statement executes.

NOTE: If you have an INSTEAD OF trigger, it is unclear to me, not having spent any real amount of time fussing with INSTEAD OF triggers, whether or not table/row constraints are enforced prior to execution of the INSTEAD OF trigger. That's something you might want to experiment with.



回答3:

This is easy to test by setting up test tables as described with print statements in the triggers and simply trying to insert invalid values.

Of course, I did it! And agree with you - get the same result from 1 to 8. And what is embarrass for me is the quote from "Microsoft SQL Server 2008 Bible" book (by Paul Nielsen). That is (on page 637):

Every transaction moves through the various checks and code in the following order:

  1. IDENTITY INSERT check
  2. Nullability constraint
  3. Data-type check
  4. INSTEAD OF trigger execution. If an INSTEAD OF trigger exists, then execution of the DML stops here. INSTEAD OF triggers are not recursive. Therefore, if the INSERT trigger executes another DML command, then the INSTEAD OF trigger will be ignored the second time around (recursive triggers are covered later in this chapter).
  5. Primary-key constraint
  6. Check constraints
  7. Foreign-key constraint
  8. DML execution and update to the transaction log
  9. AFTER trigger execution
  10. Commit transaction

So, as you see, this IT-Pro disagree with you and me. He, for example, give INSTEAD OF trigger number 4 whereas we give to it number 1. This quote just baffle me!