在大型视图上优化MySQL GROUP BY或DISTINCT

时间:2009-02-10 17:00:33

标签: mysql optimization group-by distinct performance

考虑一个由多个表组成的视图...例如v_active_car,它由加入carbody,{engine的表格wheels组成。 {1}}和stereo。它可能看起来像这样:

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)

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

4 个答案:

答案 0 :(得分:1)

你好像做得对。下一步是检查索引覆盖率。

答案 1 :(得分:1)

  1. 确保所有JOIN都有索引
    • 在您的情况下,每个级别都由一个键和一个标志选择。将标志添加为索引的一部分可能允许DB仅使用索引,而不是读取整个记录
    • 确保您有足够的RAM来保存结果集。特别是InnoDB表有很多旋钮需要调整。大多数默认值假设非常旧硬件和RAM太少。

答案 2 :(得分:0)

试试这个:

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这里应该阻止将谓词推入视图,优化器应该选择散列连接。

答案 3 :(得分:0)

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

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