2012-10-15 36 views
2

我创建了一个使用多个CTE(主要用于递归分层工作)的复杂流程。
对于小样本数据集,一切都按预期进行,但是当我将代码应用于大量数据时,我收到了意想不到的(和错误的)结果。来自CTE的意外结果

我想我已经缩小了它对CTE的影响。递归CTE是在几个较早的CTE中处理的“喂食”数据,这似乎是问题所在。

我设置了sample data set如下:

  • 四排具有独特数据
  • 每一行接收随机行数(这在一个CTE

然后加入我走第一个CTE的结果并在第二个CTE中执行自连接
我预计所有行都会加入,每个行自身都会加入,实际发生的情况是不相等的行加起来,

有人可以提供这种行为的解释吗?

+0

可能的重复http://stackoverflow.com/questions/3511353/how-many-times-are-the-results-of-this-common-table-expression-evaluated – RichardTheKiwi

回答

9

没有什么意外的结果,除非你不明白。

每个CTE都被解析each and every time它被引用。是的,这就是为什么高度事务性表上的简单CTE可能会在一个引用中返回4行,并在接下来的2个级别中返回5行。

然而,在您的示例中,这是因为ORDER BY NEWID(),给原始CTE的每个分辨率一个不同的row_number()。您是否认为CTE存储在内存中并被缓存?在SQLFiddle网站上,在您的结果下,有一个“查看执行计划”链接。它显示2个不同的独立扫描表

+2

好的答案。 OP最好的方法是将TEST_CTE的结果存储在临时表中。一旦你添加了数据并存储了由newid()定购的row_number,你可以根据需要多次引用它,现在你将会以确定的方式连接这些行 – Tobsey

+1

请你证明这部分你回答? '是的,这就是为什么一个高度事务性表上的简单CTE可能在一个引用中返回4行,在下一个2级中返回5行。'因为它们在相同的总体查询中,isn'在所有引用周围都有一个隐式事务? [*我同意ROW_NUMBER()在OP示例中解析了两次,但我不明白表的内容如何改变中间查询? (不要搞乱隔离级别等等)我并不是说你错了,只是我被这个消息吓到了,并且很想看到证据。] * – MatBailie

+0

@Dems - 所有读提交的操作确保行如果通过获得一个'S'锁定来弄脏它们,那么它们就不会被读取,然后在读取它时立即释放它。您需要重复读取以保持锁直到语句结束或可序列化以锁定范围,并防止插入与匹配谓词相匹配的新行的可能性。在任一快照隔离下,您还可以看到数据的一致视图(但这不会帮助OP的newid()问题) –