2012-10-03 154 views
5

我知道子查詢在使用不當時性能出色。我有一個非常具體的場景,用戶需要從表中檢索一組經過篩選的記錄。各種各樣的過濾器將可用,他們必須支持組合。而且,新的過濾器將由一組開發者定期創建。FROM子句中的SQL子查詢

我不喜歡一個不斷增長的單一SQL查詢與大量參數的想法。我不喜歡使用相同的SELECT語句和不同的WHERE子句的一堆自治SQL查詢的想法。我喜歡動態SQL查詢的想法,但我不確定我應該使用什麼樣的結構。我能想到的4個基本選項:(如果有更多的,我很想念,那麼請不要猶豫,建議他們)

  1. 「INNER JOIN」:通過INNER串聯過濾器連接來篩選結果。
  2. 「FROM子查詢」:通過FROM語句中的子查詢堆棧篩選器。
  3. 「WHERE子查詢」:通過WHERE子句中的子查詢來污染過濾器。
  4. 「INNER JOIN子查詢」:一個奇怪的混合。

我創建了一個SQL小提琴證明(和配置文件),其中:

http://sqlfiddle.com/#!3/4e17b/9

下面是從小提琴的摘錄提供什麼我的想法米談論:

------------------------------------------------------------------------ 
--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小提琴
  • 增加的性能測試和當地環境

回答

0

如果你總是會應用「和」邏輯,內部連接可能是一種很好的方法(我正在推廣,但它會因很多因素而異,包括你的表大小和索引等)。如果您希望能夠應用「和」或「或」過濾,則需要使用其他解決方案之一。

此外,你應該使用測試出的性能存在條款:

SELECT COUNT(*) 
     FROM @TestTable Test0 
     WHERE 
      EXISTS (SELECT 1 FROM @TestTable Test1 WHERE Test0.ID = Test1.ID AND Test1.ID % @i = 0) 
      EXISTS (SELECT 1 FROM @TestTable Test2 WHERE Test0.ID = Test2.ID AND Test2.ID % @j = 0) 
      EXISTS (SELECT 1 FROM @TestTable Test3 WHERE Test0.ID = Test3.ID AND Test3.ID % @k = 0) 
+0

增加測試的「存在」的方法。儘管我很驚訝地看到「SELECT *」和「SELECT 1」(當然不是最受控制的測試,但存在一些明確的變化)之間的某些區別,但它排在最後。 一般方法將應用於各種表格,因此大小和索引難以預先預測。我基本上在尋找「最友好的沙箱」。 – makerplays

相關問題