This is a tool I wrote to find the schemas, tables, and columns affected by an unfortunate overbroad update query in SQL Server.
- Apologies for the usage of a cursor and dynamic SQL. If you have a good way to avoid either or both, please share your solution.
- It is tested on SQL Server 2014, probably works well on later versions, and may be useful on all versions 2008 and later, albeit perhaps with some syntactic adjustments.
- I have no idea how it handles DDL changes, so be careful if your schema isn't static.
- I have not yet tested its dynamic SQL bits against SQL injection.
-
USE
the database where CDC is enabled and CDC rows are present. -
Change the first declaration of
@lsn
in the script to whatever your target starting log sequence number is. This can be found in the__$start_lsn
columns of thecdc.<whatever>_CT
tables you're interested in. -
If you want just a single (outermost?) transaction, leave the rest of the query as is. If you want all activity in all CDC-enabled tables within a time window around this transaction, adjust the initial
@start
and@end
declarations as desired, and toggle the comments on these two lines...Modify:
and __$start_lsn = @lsn --and __$start_lsn between @start and @end
to read:
--and __$start_lsn = @lsn and __$start_lsn between @start and @end
-
Uncomment the print statements if you like slightly verbose debugging output.
-
Review and run the query.
On a well-provisioned server with moderate resources, this takes some 11 seconds to report 22 affected columns across 5 affected tables, out of a possible 63 thousand columns among over 2 thousand tables, with 58 of those tables CDC-enabled. CDC cleanup job retention is set to 561600 minutes (390 days), but any high-churn tables would make this very excessive. YMMV.
- Improve interface by using options variables instead of the commented lines and hard-coded values; maybe wrap it all in a
CREATE PROCEDURE
for ease of use - Add tests, including unit tests, fuzzing, and integration tests that may find environment-specific issues
- Reimplement without any cursors or dynamic SQL
In case you're curious, I did not write or execute the query that caused the damage; I am only the DBA tasked with identifying and resolving the problem, and this audit report is one of several pieces of a larger data deep-dive investigation.
Pull requests and feedback are welcome.