关于ORDER BY结果不正确的想法



我想强调的是,我在寻找想法,而不一定是一个具体的答案,因为很难显示我的查询是什么样子,但我认为这不是必要的。

过程如下:

  1. 表A不断填满,就像一个桶一样——SQL作业每分钟或更短时间调用SP_Proc1,并将多条记录插入表A。

  2. 同时,C#进程保持每分钟或更短时间调用另一个过程SP_Proc2,从表a中进行有序的TOP5选择,并将结果返回到C#方法。C#代码完成处理结果后,从表A中删除选定的5条记录。

我把上面有问题的部分加粗了。表A中的记录必须按照指定的顺序一次处理5个,但一个月SP_Proc2会以错误的顺序选择排序的TOP 5记录,即使所有记录都存在于表A中并且具有用于排序的正确列值。

需要注意的事项:

  • 我是按整数排序的,而不是varchar
  • C#部分使用1个线程
  • SP_Proc1和SP_Proc2都使用事务,并使用READ COMMITTED或READ COMMITTED SNAPSHOT事务隔离级别
  • 用于排序的一列是一个计算值,但非常简单。它只是检查表A中的另一列是否为空,并将计算列设置为1或0
  • 主键Id上有一个唯一的非聚集索引,以及一个由SP_Proc2中用于排序的相同列组成的聚集索引
  • 我使用的是SQL Server 2012(v11.0.3000(

我开始认为这可能是一个SQL错误,或者表A中的记录或索引被损坏,然后被C#进程删除,这就是我无法捕捉到它的原因。

编辑:

为了澄清,SP_Proc1一次向表a提交一大批N条记录,SP_Poc2以5条为一批从表a中提取记录,它对表中的记录进行排序并选择前5条,有时会选择错误的批次,批次本身的排序是正确的,但应该根据ORDER BY选择不同的批次。我相信Rob Farley可能有正确的想法。

我的猜测是,您的"无序TOP5"是有序的,但后面的五个重叠。比如,一次得到1231、1232、1233、1234和1236,下一批是1235、1237,依此类推

这可能是锁定和阻塞的问题。您已经指示您的进程使用事务,所以如果您的1235尚未提交,但可以通过快照隔离忽略,并且您的1236可以被提取,我也不会感到惊讶。

听起来这里好像没有虫子。我在上面描述的是快照隔离的一个明确特性。如果必须在1236之前的批次中提取1235,则不要使用快照隔离,并强制锁定表,直到每个插入块完成。

另一种建议是在读写过程中使用表锁(tablock(。

虽然这很昂贵,但如果你想要绝对的一致性,那么这可能是一条路。

最新更新