复杂查询需要花费太多时间进行传输

时间:2014-06-05 20:00:54

标签: mysql sql

以下查询很慢,我不明白为什么。我把所有id都作为索引(一些主要的)。

SELECT r.name as tool, r.url url ,r.id_tool recId, count(*) as count, r.source as source, 
     group_concat(t.name) as instrument
FROM tools r 
INNER JOIN
 instruments_tools ifr
ON ifr.id_tool = r.id_tool
INNER JOIN
 instrument t
ON t.id= ifr.id_instrument
WHERE t.id IN (433,37,362) AND t.source IN (1,2,3)
GROUP BY r.id_tool
ORDER BY count desc,rand() limit 10;

在Wampserver安装本地,我遇到了传输数据的严重问题。有了Heidi,我看到两个“发送数据”,分别为2秒和6秒。 在共享服务器上,这是我看到的重要部分:

| statistics                     | 0.079963 |
| preparing                      | 0.000028 |
| Creating tmp table             | 0.000037 |
| executing                      | 0.000005 |
| Copying to tmp table           | 7.963576 |
| converting HEAP to MyISAM      | 0.015790 |
| Copying to tmp table on disk   | 5.383739 |
| Creating sort index            | 0.015143 |
| Copying to group table         | 0.023708 |
| converting HEAP to MyISAM      | 0.014513 |
| Copying to group table         | 0.099595 |
| Sorting result                 | 0.034256 |

考虑到我想改进查询(参见LIMIT)或删除rand()并添加权重,我有点害怕我做错了。

其他信息: 工具表大500.000行,而仪器大约6000. instruments_tools大约3M行。 查询是找到我可以用我的仪器制作的工具(通过检查t.id IN(乐器的id).Group_concat(t.name)是一种知道选择了哪种乐器的方法。

解释查询:

+----+-------------+-------+--------+-------------------------+---------------+-------- -+----------------------------+------+----------------------------------------------+
| id | select_type | table | type   | possible_keys           | key           | key_len     | ref                        | rows | Extra                                        |
+----+-------------+-------+--------+-------------------------+---------------+---------+----------------------------+------+----------------------------------------------+
|  1 | SIMPLE      | t     | range  | PRIMARY                 | PRIMARY       | 4       | NULL                       |    3 | Using where; Using temporary; Using filesort |
|  1 | SIMPLE      | ifr   | ref    | id_tool,id_instrument | id_instrument | 5       | mydb2.t.id          |  374 | Using where                                  |
|  1 | SIMPLE      | r     | eq_ref | PRIMARY                 | PRIMARY       | 4       | mydb2.ifr.id_tool |    1 |                                              |
+----+-------------+-------+--------+-------------------------+---------------+---------+----------------------------+------+----------------------------------------------+

1 个答案:

答案 0 :(得分:1)

您需要在交叉表上使用复合索引:

ALTER TABLE instruments_tools ADD KEY (id_instrument, id_tool);

该索引中列的顺序很重要!

您希望的是连接将从乐器表开始,然后根据id_instrument在复合索引中查找匹配的索引条目。然后一旦找到索引条目,它就会免费提供相关的id_tool。所以它根本不必读取instrument_tools表,它只需要读取索引条目。这应该在EXPLAIN中为instruments_tools表提供“使用索引”注释。

这应该会有所帮助,但是你无法避免使用临时表和文件排序,因为你要分组的列并且排序不能使用索引。

您可以尝试通过增加临时表可用的内存大小来避免将临时表写入磁盘:

mysql> SET GLOBAL tmp_table_size = 256*1024*1024;      -- 256MB
mysql> SET GLOBAL max_heap_table_size = 256*1024*1024; -- 256MB

这个数字只是一个例子。我不知道你的情况下临时表的大小。