sql - select语句是否可能无法识别早期查询中存在的行?

标签 sql sql-server-2008

我有一个多进程方案。因此,多个Windows应用程序从不同的PC连接到数据库。

我有两个表的简单构造:

  • 我有一个tblSessions,其中每个进程都有一个使用autoincrement int Id字段
  • 的条目
  • 我有一个tblJobs,它使用级联删除从tblSession引用ID。因此,当 session 被删除时,所有作业都将被删除。而且tblJobs具有一个autoincrement int Id字段
    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!
  • 我们在应用程序中进行更长的计算时就启动了测试,它报告了所需的信息,并成功返回了1个
  • 记录被重复插入并从tblJobs中删除。
  • 现在,程序运行30秒,直到5分钟,然后重复上述测试。现在,tblJobs记录没有显示所需的信息。测试语句返回0,因此没有包含所需信息的记录。而且执行SELECT * FROM tblJobs就像执行下一个操作一样不会显示预期的记录。 (两个SELECT语句都不是一个事务的一部分)
  • 由于缺少记录,该过程终止。如果我们不做测试,那么下一条语句将只更新静态表中的一条记录,然后从作业表中删除该记录(丢失的记录),然后继续……是的,我可以忽略这种影响,但是却使我迷失了……记录不应该消失。

  • 隔离级别应为READ COMMITED。但是我看到的情况是我看到了与READ UNCOMMITED的 session 。在寻找解决方案和我们遇到问题的原因时,我发现了这个SO链接SQL Server: Isolation level leaks across pooled connections

    我找不到某些 session 显示READ COMMITED永久隔离级别的原因。当发生错误时,我也不会说任何有关隔离级别的信息。

    我也可以说这仅在SQL Server负载很重的情况下发生。如我所见,服务器没有内存压力。

    我做了什么:
  • 我产生了完整的SQL事件探查器跟踪。我们可以将其减小为仅100000条语句。从将条目插入到tblJobs的过程开始,直到我们发现SELECT COUNT(*)FROM…WHERE…为所需记录返回0。
  • 发生错误时,我们有41个客户端在运行(tblSessions中有41个条目)。 tblLocks大约有3000条记录。
  • 在事件探查器跟踪中,我们找不到丢失记录的任何DELETE语句。我们可以找到数百个影响其他记录的更新,插入和删除。但不是我们要寻找的记录。当然,tblSession记录仍然存在,并且该 session 的其他记录也仍然存在。

  • 此外,我们创建了具有相同需求和软件的测试方案,但我们永远无法解决问题。

    对程序进行更改并将其推广给客户并非易事。因此,我无法快速提供新信息。

    所以我的问题是:

    当隔离级别为READ COMMITEDREAD UNCOMMITED时,是否存在SELECT COUNT(*)语句可能丢失先前返回的记录,但后来又不返回的记录?是否存在导致记录不出现在SELECT语句中的锁定注意事项?

    最佳答案

    是。当您处于“读取未提交”模式时,查询可以读取事务日志中尚未完全提交的数据,因此仍具有某种形式的锁定。在“读取已提交”中,您的读取将请求共享锁,并且如果插入内容具有排他锁,则必须等待。然后,您必须考虑要处理的是行锁,表锁还是页锁。可能发生页面锁定吗?第A行恰好与第Z行存在于同一页面上,正在更新第A行,因此您必须先找到第Z行,然后才能找到它。有人打开了允许页面锁定的设置吗?
    您还应该知道,在查询中使用With(nolock)会将查询的该部分放入“读未提交”中。

    观看此https://m.youtube.com/watch?v=EqfAPZGKifA

    关于sql - select语句是否可能无法识别早期查询中存在的行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52310722/

    相关文章:

    sql - 分区边界 ID(例如 sys.partition_range_values 中)是否保证按分区范围排序?

    Java类到数据库表结构

    xml - T-SQL 和 XML - 将父元素和多个子元素连接到结果集中

    作为变量插入的 MySql 过程值

    mysql - 将 mysql 查询转换为 postgres 时出错

    mysql - 如何编写存储过程

    sql - sql中如何对表进行转置

    database - 选择数据库表中的第 n 列

    sql - 如何在现有数据上重新播种/替换标识列

    sql - 转换为日期时间仅在 WHERE 子句上失败?