您如何知道自上次使用SQL表以来是否已更改?

时间:2013-11-18 01:16:54

标签: sql-server sql-server-2008 tsql sql-server-2008-r2 sql-server-2008r2-express

有没有办法知道自上次使用以来SQL Server 2008 R2表中的数据是否发生了变化?我想知道任何类型的更改 - 是否已插入新记录或已修改或删除现有记录。

我对特定的改变可能不感兴趣。我只对一个布尔值感兴趣,该值指示表数据是否已更改。

最后,我想要一个简单的解决方案,不涉及为每个CRUD操作编写触发器,然后让该触发器更新其他一些日志表。

我有C#程序,它意味着将大量初始数据插入到某些数据库表中。这是一次性操作,在应用程序的生命周期中应该只发生一次,或者很少再发生一次。但是,在开发和测试期间,我们经常使用这个程序。

目前,大约有10个表插入数据,每个表每个表大约有21,000行,程序运行大约需要45秒。这不是一个真正的大问题,因为这是一次性的操作,无论如何都要在将产品运送给客户之前在内部完成。

不过,我想尽量减少这段时间。因此,如果自我的程序上次使用以来表数据没有变化,我想不要将数据插入表中。

我的同事告诉我,我可以在T-SQL中使用CHECKSUM_AGG函数。我的问题是:

1)如果我计算CHECKSUM_AGG(Cast(NumericPrimaryKeyIdColumn AS int)),那么校验和只会在添加新行或删除现有行时更改,对吗?如果某人只修改了表中现有行的其他列的值,那么这对ID列的校验和聚合没有影响,对吧?或者会吗?

2)有没有其他方法可以解决自上次程序使用以来表数据是否发生变化的问题?

6 个答案:

答案 0 :(得分:1)

您是否调查了Change Data Capture

答案 1 :(得分:1)

您可以结合使用散列和checksum_agg。只要字符串值不溢出HASHBYTES函数,下面的方法就会起作用。它的工作原理是将所有列转换为字符串,连接它们,对连接的字符串进行散列,将散列转换为整数,将所有这些值放入临时表,然后在临时表上运行checksum_agg。可以很容易地适应所有真实表格的迭代

编辑:结合MD5和checksum_agg看起来至少对于有些狭窄的表格起作用了:

declare @tablename sysname
set @tablename  = 'MyTableName'

declare @sql varchar(max) 

set @sql = 'select convert(int,HASHBYTES(''MD5'','''''


declare c cursor for
select column_name
from INFORMATION_SCHEMA.COLUMNS
where table_name = @tablename


open c

declare @cname sysname

fetch next from c into @cname

while @@FETCH_STATUS = 0 
begin
    set @sql = @sql + '+ coalesce(convert(varchar,' + @cname + '),'')'
    fetch next from c into @cname
end


close c
deallocate c

set @sql =  @sql + ')) as CheckSumVal
into ##myresults from ' + @tablename

print @sql

exec(@sql)



select CHECKSUM_AGG(CheckSumVal) from ##myresults
drop table ##myresults

答案 2 :(得分:1)

这非常接近我已经想到的和@ user3003007提到的内容。

我想到的一种方法是为每个这样的表采用CHECKSUM(*)CHECKSUM(Columns, I, Am, Interested, In),然后对每行的校验和进行聚合校验和,如下所示:

SELECT CHECKSUM_AGG(CAST(CHECKSUM(*) as int)) FROM TableName;

这仍然不是一个可靠的方法,因为CHECKSUM不适用于某些数据类型。因此,如果我的列类型为textntext,则CHECKSUM将失败。

幸运的是,我感兴趣的列列表中没有这样的数据类型,所以这对我有用。

答案 3 :(得分:0)

您如何知道您所做的更改或更改与您的需求相关?如果你不打算正确地做(删除和重新插入或合并)那么整件事对我来说都是徒劳的。

在任何情况下,如果您只花一个小时研究,实施和测试您的更改,您必须运行它80次(并坐下来观看它),然后才能打破您的时间。那么为什么要这么麻烦呢?

答案 4 :(得分:0)

  • 添加额外列,例如last_updated default getdate()
  • 添加额外列int类型。
  • 声明枚举(启用标志属性选项以逐位执行) 操作)。
  • 然后您可以在此列上应用校验和。

没有数据类型问题。

答案 5 :(得分:0)

检查这个的简单方法是使用系统DMV来检查索引使用情况统计信息,表上的第一个索引(id 1)是表本身的堆或聚簇索引,因此可以用于检查上次更新的时间:

SELECT  DB_NAME(database_id) AS [database_name] ,
        OBJECT_NAME([object_id], [database_id]) AS [index_name] ,
        [user_seeks] ,
        [user_scans] ,
        [user_lookups] ,
        [user_updates] ,
        [last_user_seek] ,
        [last_user_scan] ,
        [last_user_lookup] ,
        [last_user_update]
FROM    sys.dm_db_index_usage_stats
WHERE   [index_id] = 1

从这里,你可以看到表格的最后一次更新以及已经有多少更新(我已经在搜索和扫描中留下了以防万一你感兴趣)。

值得注意的是,这些数据在重新启动后不会持续存在,但是将它永远加载到永久表中非常简单,以便使数据永久化。