Sql server 事务级别、nolock/readpast和并发
我们有一个系统,它可以同时插入来自多个站点的大量数据,同时还公开了一个数据查询接口。架构如下所示(很抱歉格式不好): 数据插入是在“同步”中完成的,并且是这样的(我们只向系统中插入数据,从不更新) 查询是这样的(对于给定的站点,测量时间和数据类型) 我的问题是,我们如何将INSERT上的事务级别与查询上的NOLOCK/READPAST提示结合起来,以便:Sql server 事务级别、nolock/readpast和并发,sql-server,optimization,concurrency,transactions,locking,Sql Server,Optimization,Concurrency,Transactions,Locking,我们有一个系统,它可以同时插入来自多个站点的大量数据,同时还公开了一个数据查询接口。架构如下所示(很抱歉格式不好): 数据插入是在“同步”中完成的,并且是这样的(我们只向系统中插入数据,从不更新) 查询是这样的(对于给定的站点,测量时间和数据类型) 我的问题是,我们如何将INSERT上的事务级别与查询上的NOLOCK/READPAST提示结合起来,以便: 我们在支持插入的同时最大限度地提高了系统的并发性(我们需要存储大量数据,每秒存储2000多条记录) 查询仅从“提交的”同步返回数据(我们不希望
如果您运行的是SQL 2005及以上版本,请查看实现。您将无法使用nolock获得一致的结果
在SQL 2000上解决这个问题要困难得多。这是SQL Server 2005/2008企业级分区功能的一个很好的方案。您可以为每个StationID创建一个分区,并且每个StationID的数据可以进入其自己的文件组(如果需要,可能不需要,具体取决于您的负载) 这为并发性带来了一些优势:
- 如果按stationid进行分区,则用户可以对当前未加载的stationid运行select查询,并且不会遇到任何并发问题
- 如果按stationid分区,则多个工作站可以同时插入数据,而不会出现并发问题(只要它们位于不同的文件组上)
- 如果按syncid范围进行分区,则可以将较旧的数据放在较慢的存储上
- 如果按syncid范围进行分区,并且范围足够小(意味着没有包含数千个syncid的范围),则可以在用户查询的同时进行加载,而不会出现并发问题
分区在SQLServer2008中甚至更好,尤其是在并发性方面。它仍然不是一颗灵丹妙药——它需要熟练的DBA进行手动设计和维护。它不是一个一成不变的特性,它需要企业版,这比标准版要贵。不过,我很喜欢它——我已经使用过好几次了,它为我解决了一些具体问题。将此作为答案,因为“解决方案”的一部分与正确设置特定的磁盘系统有关,这大大提高了按stationid分区的吞吐量。另一个好处是:如果您创建了正确的聚集索引(stationid,syncid)在synctable上,(syncid)在datatable上,并对syncid使用标识。您永远不会从insert活动中获得页拆分,这允许您对select语句使用READPAST,这样就不会干扰insert活动(他们不会等待获得X锁定记录的S锁,并且在没有更新的情况下,不会为任何S锁定行发出X锁)。如果可以进行页面拆分,READPAST有时可能会导致不一致的结果,这是一个危险的选项。
[SyncTable]
SyncID
StationID
MeasuringTime
[DataTypeTable]
TypeID
TypeName
[DataTable]
SyncID
TypeID
DataColumns...
INSERT INTO SyncTable(StationID, MeasuringTime) VALUES (X,Y); SELECT @@IDENTITY
INSERT INTO DataTable(SyncID, TypeID, DataColumns) VALUES
(SyncIDJustInserted, InMemoryCachedTypeID, Data)
... lots (500) similar inserts into DataTable ...
SELECT SyncID FROM SyncTable WHERE StationID = @StationID
AND MeasuringTime = @MeasuringTime
SELECT DataColumns FROM DataTable WHERE SyncID = @SyncIDJustSelected
AND DataTypeID = @TypeID