糟糕的SQL性能

时间:2013-03-22 15:34:32

标签: mysql performance

这需要72秒:

SELECT distinct(meters.id)
FROM meters, meters_tags, houses_tags, tags
WHERE (
        tags.name = "xxx" AND ((
            meters_tags.tag_id = tags.id AND
            meters_tags.meter_id = meters.id
          ) OR (
            houses_tags.tag_id = tags.id AND
            houses_tags.house_id = meters.house_id
          )
        )
      );

这需要0.00秒:

SELECT distinct(meters.id)
FROM meters, meters_tags, houses_tags, tags
WHERE (
        tags.name = "xxx" AND ((
            meters_tags.tag_id = tags.id AND
            meters_tags.meter_id = meters.id
          )
        )
      );

这需要0.00秒:

SELECT distinct(meters.id)
FROM meters, meters_tags, houses_tags, tags
WHERE (
        tags.name = "xxx" AND ((
            houses_tags.tag_id = tags.id AND
            houses_tags.house_id = meters.house_id
          )
        )
      );

两个查询中的每一个本身都不会花费时间,但是将它们组合在一起需要72秒。我也尝试将其转换为表单(query1)或(查询)而不是query0 AND((query1)OR(query2)),它也非常慢。

以下是第一个(慢)查询的描述:

+----+-------------+-------------+-------+----------------------------------------------------------------------------------------------------+------------------------------------------+---------+-------+-------+-------------------------------------------------------+
| id | select_type | table       | type  | possible_keys                                                                                      | key                                      | key_len | ref   | rows  | Extra                                                 |
+----+-------------+-------------+-------+----------------------------------------------------------------------------------------------------+------------------------------------------+---------+-------+-------+-------------------------------------------------------+
|  1 | SIMPLE      | meters_tags | index | index_meters_tags_on_tag_id_and_meter_id,index_meters_tags_on_tag_id,index_meters_tags_on_meter_id | index_meters_tags_on_tag_id_and_meter_id | 10      | NULL  |     1 | Using index; Using temporary                          |
|  1 | SIMPLE      | tags        | ref   | PRIMARY,tags_name                                                                                  | tags_name                                | 258     | const |     1 | Using where; Using index                              |
|  1 | SIMPLE      | meters      | index | PRIMARY,index_meters_on_house_id                                                                   | index_meters_on_house_id                 | 5       | NULL  | 45389 | Using index; Using join buffer                        |
|  1 | SIMPLE      | houses_tags | index | index_houses_tags_on_tag_id_and_house_id                                                           | index_houses_tags_on_tag_id_and_house_id | 10      | NULL  |  7158 | Using where; Using index; Distinct; Using join buffer |
+----+-------------+-------------+-------+----------------------------------------------------------------------------------------------------+------------------------------------------+---------+-------+-------+-------------------------------------------------------+

这些表都不大于100k行。合并这两个查询需要花费很长时间才能单独运行如此之快?似乎我需要的所有索引都存在,因为单独的子查询速度非常快。

1 个答案:

答案 0 :(得分:1)

仔细查看您的综合查询;它计算了houses_tags与meters_tags的交叉连接,排序并消除了重复项,并将其连接到查询的其余部分。两个部分查询都会立即删除houses_tags或meters_tags,并仅使用其他查询。因此速度差异很快。

建议:学习并使用现代连接语法,除非是因为它可以帮助您避免这些病态情况,直到您学会识别它们为止。