2011-03-29 105 views
2

我有一個SQL腳本(當前針對SQLite運行,但它應該可能適用於任何數據庫引擎),它使用相同的子查詢兩次,並且因爲它可能會獲取大量記錄(表中有幾百萬行)我想只打一次電話。如何避免重複IN子句的子查詢?

查詢

縮短的僞版本是這樣的:

SELECT * FROM 
    ([the subquery, returns a column of ids]) AS sq 
[a couple of joins, that fetches things from other tables based on the ids] 
WHERE thisorthat NOT IN ([the subquery again]) 

我嘗試了各種方式(帶/不帶括號使用的域名(sq),有/無命名的平方等列)但無濟於事。

難道我真的重複這個子查詢?

澄清: 我這樣做在Python和SQLite作爲什麼可以做一個小的演示,但我想我的解決方案規模以及可能用盡可能少的修改成爲可能。在真實情況下,數據庫將有幾百萬行,但在我的例子中,只有10行含有虛擬數據。因此,代碼將在例如MySQL上得到很好的優化,這絕對是足夠好的 - 它不必爲SQLite專門優化。但正如我所說,需要的修改越少越好。

+1

我不能說SQLite,但最正常的RDBMS應該能夠優化這個。對於某些產品(例如SQL Server,PostgreSQL等),可以通過使用公用表表達式來確保文本只出現一次。 – 2011-03-29 09:31:15

+0

@Damien_The_Unbeliever:鑑於SQLlite是嵌入式數據庫,一方面應該很小,並且不需要支持複雜的,長時間運行的OLAP類型查詢,那麼重量級優化器並不值得增加代碼和運行時間簡短的即席查詢。 – 2011-03-29 11:26:52

回答

7

有標準SQL一個WITH條款,但是,我不知道它是由SQLlite支持 - 儘管當然值得一試的:

WITH mySubQuery AS 
(
    [the subquery code] 
) 

SELECT * FROM 
    mySubQuery AS sq 
    [a couple of joins, that fetches things from other tables based on the ids] 
WHERE thisorthat NOT IN (mySubQuery) 

這就是說,你在這裏做將可能對於超過幾千行的任何數據集,速度會非常慢,所以如果可能的話,我會嘗試對其進行重新編程 - 一般應避免使用NOT IN,尤其是如果您還有幾個連接。

+0

這是一個很好的建議,但不幸在SQLite中不支持WITH。 – 2011-03-29 09:51:08

+0

至於性能:我想要做的是通過關係表將自己的表加入自己,並過濾一些約束,然後再次進行相同的連接。約束會在子查詢中過濾掉幾百行,所以在實際的連接中可能不會有一百萬行=) – 2011-03-29 09:55:07

+1

我仍然不明白爲什麼你需要從subQuery中選擇,然後做一個不在相同的子查詢中,不能描述如何需要。你可以發佈整個SQL,真的很感興趣,看看它不能優化。 – 2011-03-29 10:29:59

0

你可以把SELECT部分​​進入查看比你可以使用別名「SQ」

我希望這是有幫助的

4

你需要一個子查詢過濾查看結果?您可能可以使用OUTER JOIN(例如例如:

SELECT * 
    FROM [the subquery's FROM clause] AS sq 
     RIGHT OUTER JOIN [a couple of tables based on the ids] 
      ON thisorthat = sq.[a column of ids] 
WHERE sq.[a column of ids] IS NULL; 
0

一般來說,我質疑需要消除重複。 SQL編譯器可以看到兩個子查詢是相同的,如果看起來最佳,則選擇只做一次。

此外,通過在源文件中保留重複項,SQL編譯器和優化器有機會以不同的方式對待它們。例如,SQLite的子查詢展平優化可能會應用於一對重複對中的一個或對每個重複應用不同。請參閱第9.0節,子查詢展平https://www.sqlite.org/optoverview.html