【问题标题】:Optmizing MySQL GROUP BY or DISTINCT on large views在大视图上优化 MySQL GROUP BY 或 DISTINCT
【发布时间】:2009-02-10 17:00:33
【问题描述】:

考虑一个由多个表组成的视图...例如 v_active_car,它由表 car 连接到 bodyenginewheelsstereo 组成。它可能看起来像这样:

v_active_cars查看

SELECT * FROM car
    INNER JOIN body ON car.body = body.body_id
    INNER JOIN engine ON car.engine = engine.engine_id
    INNER JOIN wheels ON car.wheels = wheels.wheels_id
    INNER JOIN stereo ON car.stereo = stereo.stereo_id
    WHERE car.active = 1
    AND engine.active = 1
    AND wheels.active = 1
    AND stereo.active = 1

汽车的每个组件都有一个“活动”标志。 现在,我需要找到现役汽车中可用的所有立体声音响。 为此,需要使用整个视图,而不仅仅是 stereo 表 - 立体声处于活动状态并不意味着它可以在汽车中使用。

这样我就可以了

SELECT DISTINCT stereo_id FROM v_active_cars

尽管这可能会返回非常少的行数,但它仍然是一个非常慢的查询。

我试过了,但速度更慢:

SELECT stereo_id FROM stereo WHERE EXISTS
(SELECT 1 FROM v_active_cars WHERE stereo_id = stereo.stereo_id)

我还能做些什么来加快速度吗?

【问题讨论】:

  • 请贴出每张表有多少行以及查询需要多长时间。
  • 是的,关于每个表中的活跃和非活跃数字的一些想法,以及您从视图中返回的数字。如果它是数百万并且需要几秒钟,那么这可能就是你所希望的,如果它是数百并且需要几分钟,那么某个地方可能有问题

标签: mysql optimization group-by distinct performance


【解决方案1】:
  1. 确保所有 JOIN 都有索引
    • 在您的情况下,每个级别都由一个键和一个标志选择。将标志添加为索引的一部分可能允许数据库仅使用索引,而不是读取整个记录
    • 确保您有足够的 RAM 来保存结果集。尤其是 InnoDB 表有很多你必须调整的旋钮。大多数默认设置假定非常旧硬件和太少的 RAM。

【讨论】:

  • 您的第 3 点适用于 MySQL 的所有参数,而不仅仅是 InnoDB 的参数。
  • 是的,按照今天的标准,InnoDB 默认值特别小
【解决方案2】:

你似乎做的一切都是正确的。下一步是检查索引覆盖率。

【讨论】:

  • 索引似乎很好,不幸的是:/
  • 如果您的索引正确,那么您选择了最短的部分来获取结果集。不幸的是,现在您需要调整数据库服务器/硬件以提高性能。
【解决方案3】:

试试这个:

SELECT stereo_id
FROM stereo s, (
  SELECT *
  FROM v_active_cars
  ORDER BY stereo_id
  ) v
WHERE s.active = 1
  AND v.stereo = s.stereo_id

ORDER BY 此处应防止将谓词推入视图,优化器应选择散列连接。

【讨论】:

    【解决方案4】:

    您可以尝试为每个部分创建一个仅显示活动部分的视图,然后加入这些部分。例如。

    VIEW activeCar
    SELECT * FROM car WHERE car.active = 1
    
    VIEW activeEngine
    SELECT * FROM engine WHERE engine.active = 1
    

    那么你的最终视图可以是

    SELECT * FROM activeCar
    INNER JOIN activeEngine ON activeCar.engine = activeEngine.engine_id
    

    显然要确保您在活动列上有一个索引。

    另一种选择是在 id 和 active 标志上都有一个索引。然后,您可以在加入时执行 active=1。这样只有一个索引用于连接,而不是一个用于 id 和一个用于活动。

    SELECT * FROM car
    INNER JOIN body ON car.body = body.body_id AND body.active = 1
    INNER JOIN engine ON car.engine = engine.engine_id AND engine.active = 1
    INNER JOIN wheels ON car.wheels = wheels.wheels_id AND wheels.active = 1
    INNER JOIN stereo ON car.stereo = stereo.stereo_id AND stereo.active = 1
    

    【讨论】:

      猜你喜欢
      • 2016-08-14
      • 1970-01-01
      • 1970-01-01
      • 2017-11-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-09
      相关资源
      最近更新 更多