【问题标题】:Terrible SQL performance糟糕的 SQL 性能
【发布时间】:2013-03-22 15:34:32
【问题描述】:

这需要 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) OR (query) 而不是 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。当这两个查询单独运行得如此之快时,合并这两个查询可能需要这么长时间?似乎我需要的所有索引都存在,因为仅子查询就足够快了。

【问题讨论】:

  • 它没有回答这个问题,但你可以做(fastquery1) union all (fastquery2)。这是我在查询被ORs 减慢时使用的技巧。
  • 谢谢。此查询是自动生成的 - 可以将多个子句添加到查询中,每个子句用 AND 分隔。使用 union all 会破坏这种模式,但没关系,我可以对这个子句进行特殊处理,因为似乎没有有效的方法可以将其表示为“正常”子句。

标签: mysql performance


【解决方案1】:

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

建议:学习和使用现代连接语法,如果没有其他原因,只是因为它可以帮助您避免这些病态情况,直到您学会识别它们。

【讨论】:

  • JOIN 语法是让这个查询运行得更快还是更清楚地表明查询会变慢?
  • JOIN 语法使您可以更轻松地识别交叉连接,因此您可以更轻松地识别所编写的查询将是非执行的。然后你知道用另一种方式写它。在这种情况下,UNION 比交叉 jin 更高效。
猜你喜欢
  • 2021-04-09
  • 1970-01-01
  • 1970-01-01
  • 2011-04-26
  • 2013-02-04
  • 1970-01-01
  • 1970-01-01
  • 2015-11-23
  • 2013-05-09
相关资源
最近更新 更多