为什么我的MySQL查询这么慢?

时间:2014-02-05 11:43:02

标签: mysql sql query-optimization

我正在试图找出为什么这个查询如此缓慢(大约需要6秒才能得到结果)

SELECT DISTINCT
    c.id
FROM
    z1
        INNER JOIN
    c ON (z1.id = c.id)
        INNER JOIN
    i ON (c.member_id = i.member_id)
WHERE
    c.id NOT IN (... big list of ids which should be excluded)

这是执行计划

+----+-------------+-------+--------+-------------------+---------+---------+--------------------+--------+----------+--------------------------+
| id | select_type | table | type   | possible_keys     | key     | key_len | ref                | rows   | filtered | Extra                    |
+----+-------------+-------+--------+-------------------+---------+---------+--------------------+--------+----------+--------------------------+
|  1 | SIMPLE      | z1    | index  | PRIMARY           | PRIMARY | 4       | NULL               | 318563 |    99.85 | Using where; Using index; Using temporary |
|  1 | SIMPLE      | c     | eq_ref | PRIMARY,member_id | PRIMARY | 4       | z1.id              |      1 |   100.00 |                          |
|  1 | SIMPLE      | i     | eq_ref | PRIMARY           | PRIMARY | 4       | c.member_id        |      1 |   100.00 | Using index              |
+----+-------------+-------+--------+-------------------+---------+---------+--------------------+--------+----------+--------------------------+

是不是因为mysql几乎要拿掉整个第一张桌子?可以调整吗?

3 个答案:

答案 0 :(得分:1)

您可以尝试用子查询替换c。

SELECT DISTINCT
    c.id
FROM
    z1
        INNER JOIN
    (select c.id 
     from c 
     WHERE
       c.id NOT IN (... big list of ids which should be excluded)) c ON (z1.id = c.id)
        INNER JOIN
    i ON (c.member_id = i.member_id)

只留下必要的id

答案 1 :(得分:1)

根据您提供的信息说,是否有更快的解决方案来获取相同的数据是不可能的(我们需要知道数据分布以及必须使用哪些外键)。但是假设这是一个分层数据集,那么该计划可能不是最优的:减少行数的唯一谓词是c.id NOT IN....

在优化任何查询时要问自己的第一个问题是我是否需要所有行?这回来了多少行?

我很难在查询中看到任何返回“id”值列表(表示一组自动增量整数)的信息。

你不能使用NOT IN(或&lt;&gt;)的索引,因此最有效的解决方案可能是从'c'开始全表扫描 - 这应该是StanislavL查询的结果。< / p>

由于您不使用i和z中的值,因此连接可以替换为“exists”,可以帮助提高性能。

答案 2 :(得分:0)

我会考虑为c(id, member_id)创建复合索引。这样查询应该只在索引级别工作,而不扫描表中的任何行。