2010-05-06 64 views
2

我有一個SQL查詢在另一個表上執行LEFT JOIN,然後輸出可以耦合到指定表中的所有結果。然後我有第二個SQL查詢再次執行LEFT JOIN,然後輸出無法耦合到指定表的結果。在代碼中,這是一樣的東西:SQL以兩個或多個表作爲輸出 - 最有效的方式?

INSERT INTO coupledrecords 
SELECT b.col1, b.col2... s.col1, s.col2... FROM bigtable AS b 
LEFT JOIN smallertable AS s 
ON criterium 
WHERE s.col1 IS NOT NULL 

INSERT INTO notcoupledrecords 
SELECT b.col1, b.col2... bigtable AS b 
LEFT JOIN smallertable AS s 
ON criterium 
WHERE s.col1 IS NULL 

我的問題:我現在必須執行JOIN兩次,以達到我想要的。我有一種感覺,這是它的兩倍。這是真的,如果是的話,有沒有辦法更有效地做到這一點?

回答

4

如果要插入不同的結果到2頁不同的表,您需要2個不同的查詢。

我建議的唯一的事情,就是「coupledrecords」查詢可以只是一個INNER JOIN:

INSERT INTO coupledrecords 
SELECT b.col1, b.col2... s.col1, s.col2... FROM bigtable AS b 
INNER JOIN smallertable AS s 
ON criterium 

如果你插入到相同的表,與現場來指示是否這是一個匹配的記錄或沒有,那麼是的,你可以做它作爲一個查詢。

+0

感謝Ada&oedo! – thomaspaulb 2010-05-06 08:48:16

3

底線是,您需要2個查詢,因爲您要插入2個不同的表格。如果你只有一個表,而不是偶數記錄和不記錄記錄,那麼你可以在1個查詢中完成。 :)

+0

我想你可以插入視圖,雖然根據我的答案。不幸的是,我沒有時間去測試它,看看它是否有效,以及(b)查詢計劃是什麼樣子,以及是否有任何好處。 – 2010-05-06 09:18:56

0

你基本上是在兩個數據chope。一旦你做到了,一旦你有coupledrecords一組按鍵,應該只是做一個NOT IN

INSERT INTO notcoupledrecords 
SELECT b.col1, b.col2... bigtable AS b 
WHERE some_col not in (select some_col from coupledrecords) 
3

我認爲你可以這樣做的一種方法是創建一個分區視圖,並在列上指定耦合/非耦合的檢查約束。然後插入視圖並讓SQL Server找出目標表。不是建議你這樣做,只是想我會提及它的可能性!

INSERT INTO coupledrecordsView 
SELECT case WHEN s.col1 IS NULL THEN 1 ELSE 0 END AS IsCoupled, 
b.col1, b.col2... s.col1, s.col2... FROM bigtable AS b 
LEFT JOIN smallertable AS s 
ON criterium 
+0

哈,我剛剛發佈了一個分區視圖的答案 - 就在我發佈我的我看到你的,並在我的答案中提到它。 +1! – 2010-05-06 09:57:54

+0

雖然你的答案似乎比我的全面得多! – 2010-05-06 10:05:22

+0

很酷。看起來這會提高性能,沒有任何警告? – thomaspaulb 2010-05-06 10:14:08

2

如果你可以改變的coupledrecordsnotcoupledrecords的聚集索引包含從一列smalltable(包括每個聚集索引的最後一個套結計算位列,僅爲本purpose--看到@馬丁·史密斯的答案上面的細節),那麼你可以使用Partitioned View作爲插入。這很容易。

如果這是不可能的,那麼你也可以嘗試一個非分區視圖解決方案。請參閱下面 - 它更多參與。

不知道數據是如何分佈的(例如,行大小,可爲空與不可空列的數量,耦合與非耦合的比率),很難推薦一個通用解決方案,但一種解決方案在大多數情況下可能運行良好是使用視圖模擬單個「maybecoupled」表上的耦合和非耦合表。使用視圖意味着您現有的查詢代碼(插入除外)不必更改。乍一看,這看起來非常無效,但請記住,空值佔用零存儲空間,並且使用適當的索引,SQL不會浪費太多的過濾「其他視圖」行。

下面是它如何工作:

  • INSERT 所有記錄到基表(例如maybecoupled)在單次
  • 確保有一個指數(理想的是聚簇索引,但非聚集是也可以)在從smalltable獲得的其中一列上。我們假設這是indexedcol1
  • 在上面創建兩個視圖:coupledrecordsnotcoupledrecords,其定義是SELECT col1, ... FROM maybecoupled WHERE indexedcol1 IS NULLSELECT col1, ... FROM maybecoupled WHERE indexedcol1 IS NOT NULL
  • 如果您在indexedcol1上有聚簇索引,那麼對於大多數查詢,您將只支付很少或不支付懲罰,因爲對任一查看的每個查詢都只會觸及相應的一半記錄,而不會觸及另一半。您的非聚集索引會變大一點,因此速度會變慢一些,但即使如此,也可以通過filtered indexes來改善。
  • 如果你不能使用聚簇索引,請確保indexcol1是每個非聚簇索引的一部分(或者是INCLUDE-d)。這樣可以避免必須返回聚簇索引來查找indexcol1,以查詢只從非聚簇索引中提取數據的查詢。

這裏有一些情況下,上述方案將無法工作:

  • 如果加上行的數量相對較少,您可能已在bigtable很多非空列,或者你有很小的行。那麼所有這些非耦合行的空間開銷可能會受到影響。 (空值不佔用空間,但不可空列)
  • 如果使用的是非聚簇indexcol1並且無法更改索引以確保indexcol1存在於非聚簇索引中
  • 如果由於查詢複雜性增加導致SQL Server選擇錯誤索引以用於查詢計劃(儘管您可以使用索引提示修復此問題)

警告:您一定要測試性能任何基於視圖的解決方案,以確保它不會讓事情變得更糟 - SQL通常擅長於選擇好的查詢計劃,但並非總是如此。測試,測試,測試!

+0

我有興趣嘗試一下你的解決方案,但是我對聚簇索引以及如何操作它們幾乎沒有經驗。我想到的另一種方法是在一個表上創建一個觸發器,當該表無效時將該行重定向到另一個表。你有什麼想法如何執行? – thomaspaulb 2010-05-06 11:12:42

+0

個人而言,我不是觸發器的忠實粉絲,因爲它們在從表格中插入/更新/刪除時會導致「無形」發生。未來的開發者很容易忘記觸發器在那裏,導致意想不到的後果。對於聚集索引問題,爲什麼不將表和索引的DDL發佈到您的問題的編輯中?如果我們可以看到您的索引現在在哪裏,那麼很容易就可以告訴您視圖解決方案是容易還是困難。另外,請發佈更多有關耦合到未壓縮行數的信息 - 這對找出解決方案可能很重要。 – 2010-05-06 20:14:17

相關問題