2012-03-29 62 views
2

我有一個大的MySQL表有關項目110.000.000MySQL的簡單選擇查詢速度慢

表的設計是:

CREATE TABLE IF NOT EXISTS `tracksim` (
`tracksimID` int(11) NOT NULL AUTO_INCREMENT, 
`trackID1` int(11) NOT NULL, 
`trackID2` int(11) NOT NULL, 
`sim` double NOT NULL, 
PRIMARY KEY (`tracksimID`), 
UNIQUE KEY `TrackID1` (`trackID1`,`trackID2`), 
KEY `sim` (`sim`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8; 

現在我想查詢一個正常的查詢:

SELECT trackID1, trackID2 FROM `tracksim` 
WHERE sim > 0.5 AND 
     (`trackID1` = 168123 OR `trackID2`= 168123) 
ORDER BY sim DESC LIMIT 0,100 

EXPLAIN語句給我:

+----+-------------+----------+-------+---------------+------+---------+------+----------+----------+-------------+ 
| id | select_type | table | type | possible_keys | key | key_len | ref | rows  | filtered | Extra  | 
+----+-------------+----------+-------+---------------+------+---------+------+----------+----------+-------------+ 
| 1 | SIMPLE  | tracksim | range | TrackID1,sim | sim | 8  | NULL | 19980582 | 100.00 | Using where | 
+----+-------------+----------+-------+---------------+------+---------+------+----------+----------+-------------+ 

查詢似乎很慢(約185秒),但我不知道它是否僅僅是因爲表中的項目數量。竇你有一個提示,我可以如何加快查詢或表查找?

感謝

+0

你會得到多少火柴?我懷疑這是花費最多時間的'ORDER BY SIM DESC'。 – RedFilter 2012-03-29 14:23:12

+0

那麼,表格的目的是什麼?以及'sim','track1'和'track2'是什麼?如果沒有這個,沒有人可以分辨出餐桌設計是否有效...... – Piskvor 2012-03-29 14:25:40

+0

該表的目的是保存關於不同軌道相似性的信息。在我的情況下,我有大約200萬首歌曲(這裏我使用了一個子集)並計算相似度分數。這個分數的範圍從-1到+1,而我只保存那些大於0的分數。爲了不保存NxN項目,我只保存NxN/2軌道,因爲它是雙向的。在我的情況下,trackID2總是比trackID1小。爲了計算下一步我需要類似曲目的top-k。 – simon 2012-03-29 14:30:19

回答

2

主要是我與DRAP同意,但查詢的以下變化可能會更有效,特別是對於較大LIMIT:

SELECT TS2.* 
FROM (
    SELECT tracksimID, sim 
    FROM tracksim 
    WHERE trackID1 = 168123 
    AND sim > 0.5 
    UNION 
    SELECT trackSimID, sim 
    FROM tracksim 
    WHERE trackid2 = 168123 
    AND ts.sim > 0.5 
    ORDER BY sim DESC 
    LIMIT 0, 100 
) as PreQuery 
JOIN TrackSim TS2 USING (TrackSimID); 

需要(trackID1, sim)(trackID2, sim)指標。

+0

你是對的,查詢速度比Drap的查詢速度快一點。非常感謝(和Drap)。 – simon 2012-03-30 10:43:10

+0

所以我測試了它,每個查詢大約10秒。我試圖加速id,並且我有一個解決方案來更快地運行它。在PreQuery中,它有助於將每個查詢的結果集限制爲100個元素,因此每個查詢的結果集最大爲100,並且聯合速度更快。另外,如果您在PreQuery的第一個選擇中添加trackID2,並在第二個PreQuery選擇中添加trackID1,則不需要最後一次使用tracksim加入JOIN。它幫助我加快了整個查詢的速度,因此每個查詢約1秒。非常感謝你。 – simon 2012-03-31 09:34:29

0

嘗試篩選查詢,這樣你就不會返回全表。您也可以試試在賽道上的ID中的一個應用的索引表,例如:

CREATE INDEX TRACK_INDEX 
ON tracksim (trackID1) 

http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html

http://www.tutorialspoint.com/mysql/mysql-indexes.htm

+0

這是假設'trackID1' *假設*是唯一的;另外,使用你的新索引將排除使用'sim'索引。 – Piskvor 2012-03-29 14:29:25

+0

trackID1不是唯一的,因爲每個軌道之間的相似性已計算並且保存了(trackID1> trackID2 && sim> 0)。 – simon 2012-03-29 14:40:05

+0

@simon如果trackID1不是唯一的,你仍然可以使用我提供的索引:) – 2012-03-29 14:42:08

3

擁有110萬條記錄,我無法想象還有很多有問題的軌道ID的條目。我將不得不指標如

(trackID1, sim) 
(trackID2, sim) 
(tracksimID, sim) 

,並通過工會做了PREQUERY並加入對這一結果

select STRAIGHT_JOIN 
     TS2.* 
    from 
     (select ts.tracksimID 
      from tracksim ts 
      where ts.trackID1 = 168123 
      and ts.sim > 0.5 
     UNION 
     select ts.trackSimID 
      from tracksim ts 
      where ts.trackid2 = 168123 
      and ts.sim > 0.5 
    ) PreQuery 
     JOIN TrackSim TS2 
     on PreQuery.TrackSimID = TS2.TrackSimID 
    order by 
     TS2.SIM DESC 
    LIMIT 0, 100 
+0

這看起來非常好,我會測試它 - 謝謝 – simon 2012-03-29 15:00:53

+0

這個想法看起來不錯,但是什麼是'distinct'?無論如何,TracksimID是一個主鍵,默認情況下不帶'all'的'union'是不同的。 – piotrm 2012-03-29 16:16:49

+0

@piotrm,明顯是偶然的。我輸入了我在想忘記工會獲得下半場的情況。是的,UNION可以防止重複。感謝您發現它,我會調整它。 – DRapp 2012-03-29 16:55:08