2016-07-31 50 views
7

如果我有以下兩個表:加快選取列條件在另一個表中存在沒有重複

  1. 表「一」與2列:ID(INT)[主索引],列1 [索引]
  2. 表 「b」 與3列:id_table_a(INT),條件1(INT),條件2(INT)[所有列作爲主索引]

我可以運行下面的查詢以從表A中選擇行其中表b條件1是1

SELECT a.id FROM a WHERE EXISTS (SELECT 1 FROM b WHERE b.id_table_a=a.id && condition1=1 LIMIT 1) ORDER BY a.column1 LIMIT 50 

在這兩個表中有幾億行,這個查詢非常慢。如果我做的:

SELECT a.id FROM a INNER JOIN b ON a.id=b.id_table_a && b.condition1=1 ORDER BY a.column1 LIMIT 50 

這是相當多的瞬間,但如果有表B多匹配的行匹配,則id_table_a返回重複這一點。如果我使用SELECT DISTINCT或GROUP BY a.id刪除重複項,查詢變得非常緩慢。

這裏是一個SQLFiddle顯示查詢示例:http://sqlfiddle.com/#!9/35eb9e/10

有沒有一種方法,使沒有重複在這種情況下,加入快?

*編輯,以顯示內心的,而不是LEFT JOIN沒有做編輯,以展示移動條件下加入一個差異

*的多少並沒有多大的差別

*編輯補充LIMIT

*編輯補充ORDER BY

+0

從原始(快速)連接版本返回大約多少行? – Bohemian

+0

對不起,我現在增加了LIMIT 50的問題。它應該從數以億計的行中返回50或任何小的限制。 – JJJ

+0

是否需要'訂單'?有50個嗎? – Bohemian

回答

0
SELECT id FROM a INNER JOIN b ON a.id=b.id_table_a AND b.condition1=1 

取條件轉換的加入ON條款,這樣的指數表b可以習慣過濾。同樣使用INNER JOIN超過LEFT JOIN

然後你應該有更少的結果必須分組。

+0

感謝您的幫助。不幸的是,如果我將條件移動到內部聯接,它仍然會導致重複,並且當我添加SELECT DISTINCT或GROUP BY a.id以刪除重複時,它太慢了。 – JJJ

+0

你可以給我們一個小樣本,說明你的數據是怎樣的以及結果應該是什麼樣的?最好通過sqlfiddle。我是這樣設置的,它看起來是否正確? http://sqlfiddle.com/#!9/af1e68/3 – Philipp

+0

是的,這是完美的,但我的表格有超過1億行的每個表。這裏是解釋當我有一個簡單的加入與明顯:http://pasteboard.co/2VrzV0da6.png 這裏是解釋沒有明顯的:http://pasteboard.co/2Vs4X1rmR.png 我有一個限制50在兩個查詢順便說一句。 – JJJ

1

你可以用內部聯接嘗試不同

SELECT distinct a.id 
FROM a INNER JOIN b ON a.id=b.id_table_a AND b.condition1=1 

但使用的SELECT DISTINCT *確保你沒有獨特的ID,在這種情況下使用返回錯誤的結果

SELECT distinct col1, col2, col3 .... 
FROM a INNER JOIN b ON a.id=b.id_table_a AND b.condition1=1 

你可以還可以添加一個複合索引,也可以使用condtition1例如:key(id,condition1)

如果你可以也可以執行

ANALYZE TABLE table_name; 

兩個表上..

和另一種技術是嘗試恢復鉛表

SELECT distinct a.id 
FROM b INNER JOIN a ON a.id=b.id_table_a AND b.condition1=1 

採用最選擇性表鉛查詢

使用這似乎不同的使用指標http://sqlfiddle.com/#!9/35eb9e/15的(最後一個使用其中添加)

# USING DISTINCT TO REMOVE DUPLICATES without col and order 
EXPLAIN 
SELECT DISTINCT a.id 
FROM a 
INNER JOIN b ON a.id=b.id_table_a AND b.condition1=1 
; 
+0

我嘗試使用DISTINCT,但它減慢了極端數量的查詢。由於某種原因,與一對夫婦重複的連接速度比使用DISTINCT的連接速度快了將近一秒。當使用DISTINCT時a.id – JJJ

+0

$ condition1是一列嗎?如果是,請嘗試將此列(或相關列)添加到索引中,例如:key(id,condition1) – scaisEdge

+0

yes condition1是一列並且是帶有id_table_a的主索引的一部分,這就是爲什麼帶有重複項的連接查詢非常快的原因 – JJJ

0

裹快速版本在處理移除重複和限制的查詢:

SELECT DISTINCT * FROM (
    SELECT a.id 
    FROM a 
    JOIN b ON a.id = b.id_table_a && b.condition1 = 1 
) x 
ORDER BY column1 
LIMIT 50 

我們知道內部查詢很快。去重複和排序必須發生在某個地方。這種方式發生在最小的行集上。

請參閱SQLFiddle


選項2:

嘗試以下操作:

創建索引如下:

create index a_id_column1 on a(id, column1) 
create index b_id_table_a_condition1 on b(a_table_a, condition1) 

這些覆蓋指標 - 包含您需要的所有列的人查詢,這反過來意味着僅索引訪問數據可以實現結果。

那就試試這個:

SELECT * FROM (
    SELECT a.id, MIN(a.column1) column1 
    FROM a 
    JOIN b ON a.id = b.id_table_a 
    AND b.condition1 = 1 
    GROUP BY a.id) x 
ORDER BY column1 
LIMIT 50 
+0

哇謝謝,我認爲這是迄今爲止最接近的。我怎麼去增加一個限制。如果對內部查詢有限制,並且對外部有限制,則整個查詢會非常緩慢。一些行有100k +重複項。 – JJJ

+0

沒有避免訂購,它具有O(n log n)時間複雜度。我認爲這是你的(不幸的是)不可避免的問題。 – Bohemian

+0

嘗試發佈新的查詢。它可能運作良好。 100K不是要排序的「大」行數。 – Bohemian

1

它看起來像我找到了答案。

SELECT a.id FROM a 
INNER JOIN b ON 
    b.id_table_a=a.id && 
    b.condition1=1 && 
    b.condition2=(select b.condition2 from b WHERE b.id_table_a=a.id && b.condition1=1 LIMIT 1) 
ORDER BY a.column1 
LIMIT 5; 

我不知道是否有缺陷,如果是的話請告訴我。如果有人有辦法壓縮這個不知何故,我會很樂意接受你的答案。

+0

我簡直不敢相信這個人會比原來的EXISTS解決方案更快,直到我測試它。性能差異很大。以下是該解決方案的一些變體:http://sqlfiddle.com/#!9/09ac84/15 - 前兩個條件不需要使用子查詢。最後一個條件是刪除重複項的條件。 –

+0

是的,我無法相信它,要麼直到我測試它,它是現在(幾乎瞬間)和最簡單的(當壓縮時)其中最快的解決方案。感謝您的壓縮版本。我太累了,不能注意到2個子查詢是不必要的,但由於某種原因,可能是由於優化器緩存,它與您擁有的壓縮版本一樣快。如果您使用壓縮版本編輯答案,那麼我將接受該答案,因爲它是迄今爲止所有答案中最正確和最具性能的答案 – JJJ

+0

@jjj AFAICT這與您的原始查詢不同,因爲新查詢限制'條件2「是所有可能值的單個隨機選擇值。爲了相同,你需要改變'b.condition2 =(從b選擇b.condition2 WHERE b.id_table_a = a.id && b.condition1 = 1 LIMIT 1)'到'b.condition2 IN(選擇b。 condition2 from b WHERE b.id_table_a = a.id && b.condition1 = 1)' - 即刪除'LIMIT' – Bohemian

0

使用您快速查詢子查詢中,並刪除外重複的選擇:

SELECT DISTINCT sub.id 
FROM (
    SELECT a.id 
    FROM a 
    INNER JOIN b ON a.id=b.id_table_a && b.condition1=1 
    WHERE b.id_table_a > :offset 
    ORDER BY a.column1 
    LIMIT 50 
) sub 

因爲刪除重複,你可能會得到不到50行的。只要重複查詢,直到你得到一些行。從:offset = 0開始。在以下查詢中使用上一個結果的最後一個ID作爲:offset

如果你知道你的統計數據,你也可以使用兩個限制。內部查詢的限制應足夠高,以足夠高的概率返回50個不同的行。

SELECT DISTINCT sub.id 
FROM (
    SELECT a.id 
    FROM a 
    INNER JOIN b ON a.id=b.id_table_a && b.condition1=1 
    ORDER BY a.column1 
    LIMIT 1000 
) sub 
LIMIT 50 

例如:如果在內部查詢平均每個ID,LIMIT 1000 10次重複將返回的100個不同的行的平均。這是不太可能的,你得到少於50行。

如果condition2列是布爾值,那麼您知道最多可以有兩個重複項。在這種情況下,內部查詢中的LIMIT 100就足夠了。

+0

平均差異很大。許多行有100k +重複項(可能其中一些爲100萬,但我沒有檢查)。所以限制100000會很慢,因爲我在真實世界中收集的不僅僅是id。 – JJJ

相關問題