Teradata
最佳實踐 - 使用派生表還是在連接中使用原始表?
想像一下,我在 Teradata 中有以下表格:
TableA : Field1|Field2|Field3 TableB : Field1|Field4|Field5
我正在嘗試加入這兩個表
方法一:
SEL TableA.Field3, TableB.Field4 FROM TableA LEFT JOIN TableB ON TableA.Field1 = TableB.Field1 WHERE TableB.Field5<>0
方法二:
SEL TableA.Field3, TableB.Field4 FROM TableA LEFT JOIN TableB ON TableA.Field1 = TableB.Field1 AND TableB.Field5<>0
方法3:
SEL TableA.Field3, TableB.Field4 FROM TableA LEFT JOIN ( SEL Field1 ,Field4 FROM TableB WHERE Field5<>0 ) DTable ON TableA.Field1 = DTable.Field1
問題:我總是選擇方法 3。但最近我的同事建議這不是最佳編碼實踐,因為它在連接中使用子查詢。有沒有類似聯接的編碼標準?
你的同事是對的。方法 3 的子查詢會浪費計算。因此使用方法 2。
方法 1 和方法 3 不會產生相同的結果。方法一中的
WHERE
子句在加入表後進行過濾。實際上,它將LEFT JOIN
轉換為INNER JOIN
.方法 2 等效於方法 3,因為該
AND
子句在連接之前對 TableB 執行過濾器(這是派生查詢所做的)。我創建了一個說明案例的SQLFiddle。完整程式碼如下:
CREATE TABLE TableA( Field1 int , Field2 varchar(10) , Field3 varchar(10) ); CREATE TABLE TableB( Field1 int , Field4 varchar(10) , Field5 int); INSERT INTO TableA SELECT 0, 'Zero', 'Inner' UNION ALL SELECT 1, 'One', 'Inner' UNION ALL SELECT 2, 'Two', 'Left'; INSERT INTO TableB SELECT 0, 'Zero', 0 UNION ALL SELECT 1, 'One', 1 UNION ALL SELECT 5, 'Five', 5; SELECT TableA.Field1 , TableA.Field2 , TableA.Field3 , TableB.Field4 , TableB.Field5 INTO Method1 FROM TableA LEFT JOIN TableB on TableA.Field1 = TableB.Field1 WHERE TableB.Field5 <> 0; SELECT TableA.Field1 , TableA.Field2 , TableA.Field3 , TableB.Field4 , TableB.Field5 INTO Method2 FROM TableA LEFT JOIN TableB on TableA.Field1 = TableB.Field1 AND TableB.Field5 <> 0; SELECT TableA.Field1 , TableA.Field2 , TableA.Field3 , DTable.Field4 , DTable.Field5 INTO Method3 FROM TableA LEFT JOIN (SELECT * FROM TableB WHERE TableB.Field5 <> 0) DTable on TableA.Field1 = DTable.Field1; SELECT * FROM Method1; SELECT * FROM Method2; SELECT * FROM Method3;
Teradata 的優化器很可能會將方法 3 重寫為與方法 2 相同的查詢計劃。方法 1 將導致 INNER JOIN,因為對
RIGHT
錶的限定不應該在 WHERE 子句中,而是在OUTER JOIN
條件的 ON 子句中。如果您要在方法 3 的派生表中放置一個聚合步驟(例如 DISTINCT 或 GROUP BY),您會發現優化器可能會將派生表作為單獨的步驟來滿足,而無需重新編寫計劃。我建議您為每個查詢執行 EXPLAIN 並比較輸出。