2016-01-28 50 views
2

我有兩個表,每個包含6M行。我試圖加入兩個使用內部連接,但查詢運行了2天沒有完成。中的連接的(請注意我用count(*)只是爲了讓我跑的解釋,實際上,我在CTAS使用join):MySQL內部連接非常慢的查詢

SELECT count(*) 
FROM table1 t1, 
    table2 t2 
WHERE t1.col1 = t2.colA 
    AND t1.col2 = t2.colB; 

有點調查後我發現下面的查詢運行良好:

SELECT count(*) 
FROM 
    (SELECT * 
    FROM table1) t1, 

    (SELECT * 
    FROM table2) t2 
WHERE t1.col1 = t2.colA 
    AND t1.col2 = t2.colB; 

,代替表之間唯一的區別,我使用子查詢SELECT * FROM table;

運行解釋計劃顯示後者查詢在選擇table2時構建索引。而第一個查詢使用連接緩衝區(塊嵌套循環)。

當然,MySQL很聰明,可以確定兩個查詢幾乎完全相同,並且對兩個查詢都做同樣的事情?我不明白爲什麼需要索引,因爲無論如何都需要全面掃描這兩個表。這些是臨時/暫時表格,所以如果我確實放了一個索引,它實際上就是執行這個連接。

有沒有辦法通過MySQL配置來解決這個問題?

+0

你可以爲兩個選擇發佈解釋嗎?你的mysql的版本是什麼? – Shadow

回答

1

你需要對錶中的至少一個指標,甚至如

create index Temp1 on Table2 (colA, colB) 

所以,從表1中查詢連接到表2,因此,即使表掃描是所有表1 ,你需要它快速找到表2中匹配的記錄。如果NEITHER有一個索引,那麼就這樣想。對於Table1中的每個記錄,掃描表2中的所有記錄並獲取與ColA ColB匹配的所有記錄。現在,返回到表1的第二條記錄...回到表2的所有記錄,直到它找到一個匹配。

因爲你有6M記錄,你幾乎可以在性能上扼殺一頭牛(這麼說)。通過使用索引(即使在SECOND表上),當查詢位於第一個記錄時,它可以立即跳轉到與ColA,ColB匹配的行,並且只要這些A/B記錄完成,它就返回到第一個表。

現在,其他開銷效率。如果您在兩個Col1,Col2和ColA,ColB上都有索引表,那麼引擎將在其內存/緩存中爲每個公共區域分配一整塊記錄,而不必一直返回原始數據頁面其他元素反覆。

因此,即使您認爲它可能不實際,處理大型表查詢仍然很好。此外,如果第一個表中有多個記錄,其中Col1,Col2的值相同,但表中其他列的值不同,並且第二個表中的多個ColA ColB類似,則會得到笛卡爾結果。請考慮以下情形

Table1 
Col1 Col2 OtherColumn 
X  Y  blah1 
X  Y  blah2 
X  Y  blah3 


Table2 
ColA ColB OtherColumn 
X  Y  second blah1 
X  Y  second blah2 
X  Y  second blah3 

一個簡單的查詢,就像你有

SELECT count(*) 
FROM table1 t1, 
    table2 t2 
WHERE t1.col1 = t2.colA 
    AND t1.col2 = t2.colB; 

將導致9計數你有6M的記錄和可能的笛卡爾結果呢?希望這可以澄清您可能遇到的一些問題。

+0

感謝您的回覆。我明白你對跨產品的看法,如果我必須添加一個索引,那就這樣吧。但是它足夠聰明,可以優化第二個查詢,爲什麼不是第一個呢?我的理解是,索引主要用於當您嘗試訪問數據的一部分時,因此查找大集合的速度要快得多。我相當確定甲骨文不需要索引。 –

+0

@AndrewEdwards,USE INDEXES。您正在訪問數據的一個子集。每當您在表「A」的記錄1中時,您只關心表「B」中與表「A」記錄關聯的(ColA,ColB)記錄匹配的記錄子集。否則,您正在掃描第二個表格中的每一行......現在您是否知道您正在使用數據的子集? – DRapp