2014-07-02 57 views
2

我有以下查詢(MySQL)非常慢(約15秒)。我改變了列和表的名字,所以很抱歉,如果它有任何類型的錯誤;原始查詢正在工作,只保留這個概念,沒有字面查詢。兩個表之間的SQL查詢效率

SELECT 
id, 
b, 
(SELECT MAX(day) 
FROM all_days 
WHERE all_days.id = X.id 
) AS day 
FROM X 

請注意,all_days有超過200萬行。我有3個索引:一個用於id,其他用於一天,另一個用於{id,day}

但是,如果我用UNION將查詢分爲N個查詢,則只需約1秒鐘或更少時間,結果相同:

<?php 
$ids = getIds(); // get all ID from X with a query 
$i = 0 
foreach ($ids as $id) { 
    if ($i++ > 0) { 
     $query .= " UNION "; 
    } 
    $query .= "SELECT MAX(day) 
    FROM all_days 
    WHERE all_days.id = $id"; 

} 
?> 

任何想法,我怎麼能提高速度而不做聯盟?

編輯(添加結構):

Table X: 
id INTEGER PRIMARY KEY 
b INTEGER -- extra info 

Table all_days: 
day_id INTEGER PRIMARY KEY 
id INTEGER FK X.id 
day DATETIME 

all_days indexes: 
id 
day 
id,day 
+1

它是不是從你清楚問題 - 有'all_days.id'上的索引嗎? – Turophile

+0

請發佈您的表格定義和用於完成信息的索引 – Dubas

+0

謝謝您的意見。我已經添加了結構。 – kanashin

回答

2

請有此查詢一試:

SELECT 
id, 
b, 
max_day 
FROM X 
INNER JOIN 
(
    SELECT id, MAX(`day`) AS max_day 
    FROM all_days 
    GROUP BY id 
) AS max_days 
ON max_days.id = X.id 

之所以這樣要快很多的,這裏每ID最大(日)存儲在內存中(如果太大,則存儲在磁盤上的臨時表中),然後連接到表X.在您的查詢中,讀取表X的每一行以及查詢表all_days的每一行。

+0

@ user3796513你試過了嗎? – Strawberry

+0

完美,謝謝。我必須瞭解爲什麼這個INNER JOIN如此高效(0.0006秒)與原始子查詢相比。 – kanashin

+1

@ user3796513原因很簡單,在這裏每個ID最大(天)存儲在磁盤上的內存或臨時表,如果太大,然後連接到表X.在您的查詢中,您閱讀表X的每一行,併爲每排您查詢表all_days。你經歷的速度非常慢。用'union'的方法根本沒有意義,我必須說;) – fancyPants

0

在這樣一個簡單的情況下(假設X.id/XB是獨一無二的組合),那麼這可以,而不需要一個子查詢來實現: -

SELECT X.id, 
     X.b, 
     MAX(all_days.day) AS day 
FROM X 
LEFT OUTER JOIN all_days 
ON all_days.id = X.id 
GROUP BY X.id, X.b 
+0

非常感謝您的評論。你的版本也在工作,但它需要大約3秒鐘,而@fancyPants的花費少於0.001秒。我不知道爲什麼有這麼多的差異。 – kanashin

+0

通常對於這樣的簡單查詢,它會更快,因爲它可以使用索引進行連接。 MySQL很難加入到子查詢中(當子查詢中只有少數記錄時,這不是一個真正的問題),這可能會影響@fancyPants解決方案。在all_days表中覆蓋id和day(按此順序)的覆蓋索引應該有效地加入。使用INNER JOIN會有所幫助,但如果X在all_days中記錄不匹配,則無法應對(fancyPants解決方案無論如何都存在此問題)。你可以在桌子上以EXPLAIN的形式運行這個查詢併發布結果。 – Kickstart