2012-10-15 39 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()問題) –