2014-05-09 21 views
1

我有一個看起來像這樣的數據庫方案(見http://sqlfiddle.com/#!2/4c9b4/1/0):SQL查詢性能優化 - 取最大值(B)爲對應的A

create table t(id int, dataA int, dataB int); 
insert into t select 1 ,1 ,1; 
insert into t select 2 ,1 ,2; 
insert into t select 3 ,1 ,3; 
insert into t select 4 ,2 ,1; 
insert into t select 5 ,2 ,2; 
insert into t select 6 ,2 ,4; 
insert into t select 7 ,3 ,1; 
insert into t select 8 ,3 ,2; 
insert into t select 9 ,4 ,1; 

和SQL查詢,以獲取「數據A」的列表最大的「數據B」對應於「數據A」

SELECT * FROM t a WHERE dataB = (SELECT MAX(dataB) FROM t b WHERE b.dataA = a.dataA) 

它的工作原理確定,但它可能需要長達90秒的在我的數據集運行。

如何提高此查詢的性能?

回答

2

也許MySQL重複執行子查詢,即使重複dataA。以下語句僅爲每個dataA找到一次max(dataB)。剩下的就是一個簡單的連接。希望這會更快。

select t.* 
from t 
join (select dataA, max(dataB) as maxDataB from t group by dataA) max_t 
    on t.dataA = max_t.dataA and t.dataB = max_t.maxDataB; 

編輯:這是你的SQL小提琴:http://sqlfiddle.com/#!2/4c9b4/2

+0

+1:在我的經驗中,MySQL確實非常普遍,因爲這種類型的JOIN比使用相關的子查詢要快得多。也就是說,至少在'dataA'上或最好在'dataA,dataB'上應該有一個'INDEX'。 – MatBailie

+0

確實。這工作得很好,很快。我現在發現我得到了一些重複的數據,但這是一個單獨的問題。謝謝 –

1

MySQL不會很好地完成聚合。首先要嘗試的是索引:

create index t_dataA_dataB on t(dataA, dataB); 

這可能會解決問題。二是使用下面的技巧:

select a.* 
from t a 
where not exists (select 1 
        from t a2 
        where a2.dataA = a.dataA and 
         a2.dataB > a.dataB 
       ); 

這些將「讓我最大」,以等價的:「讓我從t所有行,那裏有與同dataA沒有行和更大的dataB」 。

+0

+1:由於我在MySQL中使用相關子查詢的經驗不足,我甚至沒有考慮過'NOT EXISTS'。你有任何基準或經驗來說明'NOT EXISTS()'模式與'tbl JOIN(SELECT a,MAX(b)FROM tbl GROUP BY a)'模式的比較嗎? – MatBailie