2012-03-29 45 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