我知道子查詢在使用不當時性能出色。我有一個非常具體的場景,用戶需要從表中檢索一組經過篩選的記錄。各種各樣的過濾器將可用,他們必須支持組合。而且,新的過濾器將由一組開發者定期創建。FROM子句中的SQL子查詢
我不喜歡一個不斷增長的單一SQL查詢與大量參數的想法。我不喜歡使用相同的SELECT語句和不同的WHERE子句的一堆自治SQL查詢的想法。我喜歡動態SQL查詢的想法,但我不確定我應該使用什麼樣的結構。我能想到的4個基本選項:(如果有更多的,我很想念,那麼請不要猶豫,建議他們)
- 「INNER JOIN」:通過INNER串聯過濾器連接來篩選結果。
- 「FROM子查詢」:通過FROM語句中的子查詢堆棧篩選器。
- 「WHERE子查詢」:通過WHERE子句中的子查詢來污染過濾器。
- 「INNER JOIN子查詢」:一個奇怪的混合。
我創建了一個SQL小提琴證明(和配置文件),其中:
下面是從小提琴的摘錄提供什麼我的想法米談論:
------------------------------------------------------------------------
--THIS IS AN EXCERPT FROM THE SQL FIDDLE -- IT IS NOT MEANT TO COMPILE--
------------------------------------------------------------------------
--
--"INNER JOIN" test
SELECT COUNT(*)
FROM
@TestTable Test0
INNER JOIN @TestTable Test1 ON Test1.ID=Test0.ID AND Test1.ID % @i = 0
INNER JOIN @TestTable Test2 ON Test2.ID=Test0.ID AND Test2.ID % @j = 0
INNER JOIN @TestTable Test3 ON Test3.ID=Test0.ID AND Test3.ID % @k = 0
--
--"FROM subqueries" test
SELECT COUNT(*) FROM (
SELECT * FROM (
SELECT * FROM (
SELECT * FROM @TestTable Test3 WHERE Test3.ID % @k = 0
) Test2 WHERE Test2.ID % @j = 0
) Test1 WHERE Test1.ID % @i = 0
) Test0
--
--"WHERE subqueries" test
SELECT COUNT(*)
FROM @TestTable Test0
WHERE
Test0.ID IN (SELECT ID FROM @TestTable Test1 WHERE Test1.ID % @i = 0)
AND Test0.ID IN (SELECT ID FROM @TestTable Test2 WHERE Test2.ID % @j = 0)
AND Test0.ID IN (SELECT ID FROM @TestTable Test3 WHERE Test3.ID % @k = 0)
--
--"INNER JOIN subqueries" test
SELECT COUNT(*)
FROM
TestTable Test0
INNER JOIN (SELECT ID FROM TestTable WHERE ID % @i = 0) Test1 ON Test1.ID=Test0.ID
INNER JOIN (SELECT ID FROM TestTable WHERE ID % @j = 0) Test2 ON Test2.ID=Test0.ID
INNER JOIN (SELECT ID FROM TestTable WHERE ID % @k = 0) Test3 ON Test3.ID=Test0.ID
--
--"EXISTS subqueries" test
SELECT COUNT(*)
FROM TestTable Test0
WHERE
EXISTS (SELECT 1 FROM TestTable Test1 WHERE Test1.ID = Test0.ID AND Test1.ID % @i = 0)
AND EXISTS (SELECT 1 FROM TestTable Test2 WHERE Test2.ID = Test0.ID AND Test2.ID % @j = 0)
AND EXISTS (SELECT 1 FROM TestTable Test3 WHERE Test3.ID = Test0.ID AND Test3.ID % @k = 0)
排名(時間來執行測試)
SQL小提琴:
|INNER JOIN|FROM SUBQUERIES|WHERE SUBQUERIES|INNER JOIN SUBQUERIES|EXISTS SUBQUERIES|
-------------------------------------------------------------------------------------
| 5174 | 777 | 7240 | 5478 | 7359 |
本地環境:(無緩存:每次測試前清除緩存)
|INNER JOIN|FROM SUBQUERIES|WHERE SUBQUERIES|INNER JOIN SUBQUERIES|EXISTS SUBQUERIES|
-------------------------------------------------------------------------------------
| 3281 | 2851 | 2964 | 3148 | 3071 |
本地環境:(帶緩存:連續運行的查詢兩次,記錄第二次運行時間)
|INNER JOIN|FROM SUBQUERIES|WHERE SUBQUERIES|INNER JOIN SUBQUERIES|EXISTS SUBQUERIES|
-------------------------------------------------------------------------------------
| 284 | 50 | 3334 | 278 | 408 |
每種解決方案都有其優點/缺點。 WHERE子句中的子查詢有非常糟糕的性能。 FROM子句中的子查詢具有相當不錯的性能(實際上它們通常表現最好)(注意:我相信這種方法會否定索引的好處?)。 INNER JOIN具有相當不錯的性能,儘管它引入了一些有趣的範圍問題,因爲與子查詢不同,INNER JOINs將在相同的上下文中操作(必須是中介系統以避免表別名的衝突)。
總的來說,我認爲最簡潔的解決方案是FROM子句中的子查詢。過濾器很容易編寫和測試(因爲與INNER JOIN不同,它們不需要提供上下文/基本查詢)。
想法?這是子查詢的有效用法還是等待發生的災難?
更新(2012年10月4日):
- 更新SQL小提琴包括測試 「存在」 的方法從SQL小提琴
- 增加的性能測試和當地環境
增加測試的「存在」的方法。儘管我很驚訝地看到「SELECT *」和「SELECT 1」(當然不是最受控制的測試,但存在一些明確的變化)之間的某些區別,但它排在最後。 一般方法將應用於各種表格,因此大小和索引難以預先預測。我基本上在尋找「最友好的沙箱」。 – makerplays