我有一个多进程方案。因此,多个Windows应用程序从不同的PC连接到数据库。
我有两个表的简单构造:
tblSession中的记录会定期更新。创建和删除记录是一种罕见的事件。
tblJobs被大量使用。记录通过
INSERT INTO
插入。所有较大的操作都首先在tblJobs上执行
TABLOCKX
,以防止出现任何死锁情况。使用给定作业的特定ID的简单
DELETE
从中删除记录。 tblJobs中的条目数约为100-5000条记录。每行包含5个INT,1个DATETIME字段和1个UID。所以桌子真的很小。因此,它不是大量记录,但是我们在表上运行着永久性
INSERT/DELETE
语句。
我们在客户站点上运行我们的软件并使用SQL Server 2008(标准版)时发现问题。
我们实施了一些测试程序,并隔离出一个真正的奇怪效果,这种效果出现在我们的客户身上。
SELECT COUNT(*) FROM tblJobs WHERE Data=…
以检查我们收集的信息是否仍然正确。通常,此查询应始终返回1! SELECT * FROM tblJobs
就像执行下一个操作一样不会显示预期的记录。 (两个SELECT语句都不是一个事务的一部分)隔离级别应为
READ COMMITED
。但是我看到的情况是我看到了与
READ UNCOMMITED
的 session 。在寻找解决方案和我们遇到问题的原因时,我发现了这个SO链接
SQL Server: Isolation level leaks across pooled connections
我找不到某些 session 显示
READ COMMITED
永久隔离级别的原因。当发生错误时,我也不会说任何有关隔离级别的信息。
我也可以说这仅在SQL Server负载很重的情况下发生。如我所见,服务器没有内存压力。
我做了什么:
此外,我们创建了具有相同需求和软件的测试方案,但我们永远无法解决问题。
对程序进行更改并将其推广给客户并非易事。因此,我无法快速提供新信息。
所以我的问题是:
当隔离级别为
READ COMMITED
或
READ UNCOMMITED
时,是否存在SELECT COUNT(*)语句可能丢失先前返回的记录,但后来又不返回的记录?是否存在导致记录不出现在SELECT语句中的锁定注意事项?
请您参考如下方法:
是。当您处于“读取未提交”模式时,查询可以读取事务日志中尚未完全提交的数据,因此仍具有某种形式的锁定。在“读取已提交”中,您的读取将请求共享锁,并且如果插入内容具有排他锁,则必须等待。然后,您必须考虑要处理的是行锁,表锁还是页锁。可能发生页面锁定吗?第A行恰好与第Z行存在于同一页面上,正在更新第A行,因此您必须先找到第Z行,然后才能找到它。有人打开了允许页面锁定的设置吗?
您还应该知道,在查询中使用With(nolock)会将查询的该部分放入“读未提交”中。
观看此https://m.youtube.com/watch?v=EqfAPZGKifA