Sql server SQL 2008表中列中的所有记录更新为NULL

Sql server SQL 2008表中列中的所有记录更新为NULL,sql-server,null,sql-update,Sql Server,Null,Sql Update,每年大约有5次,我们最关键的一个表有一个特定的列,其中所有值都替换为NULL。我们已经对此运行了日志探索器,我们看不到任何使用更新填充的登录名/主机名,我们只能看到记录已更改。我们已经在服务器上的所有数据库上搜索了所有存储过程、函数等,以查找与此表相关的任何更新语句。表对此列没有外键约束。它是在更新期间建立的整数值,但更新是特定于标识键的。此字段上还有一个索引。除了t-sql update语句之外,还有什么可以导致这种情况的建议吗?我会从尽可能拒绝任何客户端动态sql开始。审计存储过程以确保它们

每年大约有5次,我们最关键的一个表有一个特定的列,其中所有值都替换为NULL。我们已经对此运行了日志探索器,我们看不到任何使用更新填充的登录名/主机名,我们只能看到记录已更改。我们已经在服务器上的所有数据库上搜索了所有存储过程、函数等,以查找与此表相关的任何更新语句。表对此列没有外键约束。它是在更新期间建立的整数值,但更新是特定于标识键的。此字段上还有一个索引。除了t-sql update语句之外,还有什么可以导致这种情况的建议吗?

我会从尽可能拒绝任何客户端动态sql开始。审计存储过程以确保它们执行正确的sql(包括正确的where子句)要容易得多。除非您的sql server严重损坏,否则更新数据的唯一方法就是使用针对它运行的sql

所有存储的进程、脚本等都应在允许运行之前进行审核

如果您没有mojo来强制执行no动态客户机sql,请添加应用程序日志记录,以便在执行每个客户机sql之前捕获它。就我个人而言,当where子句丢失时,我会让日志记录例程抛出一个异常(在记录它之后),但至少,您应该能够通过查看日志来确定下次数据被吹出的位置。确保您的日志捕获了足够的信息,您可以将其追溯到确切的来源。为执行的每个可能的动态sql语句分配一个唯一的“名称”,例如,每个程序分配一个3字符的代码,然后在程序中为每个可能的调用编号1..nn,这样您就可以知道哪个调用在“abc123”处破坏了您的数据,以及有缺陷的确切sql

补充评论

这是我后来想到的。您可以在sql表上添加/修改update触发器,以查看行数update。如果行数超过对您的应用程序有意义的阈值,则可以阻止更新。所以,做了一点搜索,发现有人已经在这个片段

CREATE TRIGGER [Purchasing].[uPreventWholeUpdate] 
ON [Purchasing].[VendorContact] 
FOR UPDATE AS 
BEGIN
     DECLARE @Count int
     SET @Count = @@ROWCOUNT;

     IF @Count >= (SELECT SUM(row_count)
         FROM sys.dm_db_partition_stats 
         WHERE OBJECT_ID = OBJECT_ID('Purchasing.VendorContact' ) 
         AND index_id = 1)
     BEGIN
         RAISERROR('Cannot update all rows',16,1) 
         ROLLBACK TRANSACTION
         RETURN;
     END
END
虽然这并不是真正正确的修复方法,但如果您适当地记录这一点,我敢打赌您可以找出是什么试图破坏您的数据并进行修复


祝你好运

如果可能的话,我会从拒绝任何客户端动态SQL开始。审计存储过程以确保它们执行正确的sql(包括正确的where子句)要容易得多。除非您的sql server严重损坏,否则更新数据的唯一方法就是使用针对它运行的sql

所有存储的进程、脚本等都应在允许运行之前进行审核

如果您没有mojo来强制执行no动态客户机sql,请添加应用程序日志记录,以便在执行每个客户机sql之前捕获它。就我个人而言,当where子句丢失时,我会让日志记录例程抛出一个异常(在记录它之后),但至少,您应该能够通过查看日志来确定下次数据被吹出的位置。确保您的日志捕获了足够的信息,您可以将其追溯到确切的来源。为执行的每个可能的动态sql语句分配一个唯一的“名称”,例如,每个程序分配一个3字符的代码,然后在程序中为每个可能的调用编号1..nn,这样您就可以知道哪个调用在“abc123”处破坏了您的数据,以及有缺陷的确切sql

补充评论

这是我后来想到的。您可以在sql表上添加/修改update触发器,以查看行数update。如果行数超过对您的应用程序有意义的阈值,则可以阻止更新。所以,做了一点搜索,发现有人已经在这个片段

CREATE TRIGGER [Purchasing].[uPreventWholeUpdate] 
ON [Purchasing].[VendorContact] 
FOR UPDATE AS 
BEGIN
     DECLARE @Count int
     SET @Count = @@ROWCOUNT;

     IF @Count >= (SELECT SUM(row_count)
         FROM sys.dm_db_partition_stats 
         WHERE OBJECT_ID = OBJECT_ID('Purchasing.VendorContact' ) 
         AND index_id = 1)
     BEGIN
         RAISERROR('Cannot update all rows',16,1) 
         ROLLBACK TRANSACTION
         RETURN;
     END
END
虽然这并不是真正正确的修复方法,但如果您适当地记录这一点,我敢打赌您可以找出是什么试图破坏您的数据并进行修复


祝您好运

事务日志资源管理器应该能够看到谁在何时执行了该命令,以及该命令的具体执行情况


您使用哪个日志资源管理器?如果正在使用,则需要启用连接监视器功能以捕获其他登录详细信息。

事务日志资源管理器应该能够查看谁执行了该命令,何时执行,以及该命令的具体外观


您使用哪个日志资源管理器?如果您正在使用,则需要启用连接监视器功能以捕获其他登录详细信息。

这可能类似于使用大锤敲打图钉,但您是否考虑过使用SQL Server审核(前提是您使用的是SQL Server Enterprise 2008或更高版本)?

这可能就像用大锤敲打图钉一样,但您是否考虑过使用SQL Server审核(如果您使用的是SQL Server Enterprise 2008或更高版本)?

是否使用脚本升级/迁移数据库?是否使用脚本升级/迁移数据库?