【问题标题】:Speed Up: query with a GROUP BY加速:使用 GROUP BY 查询
【发布时间】:2015-05-29 11:58:36
【问题描述】:

我使用下面的查询来选择电影年龄最小的演员。

SELECT production_cast.production_id, MIN(birthdate) FROM person
LEFT JOIN production_cast ON production_cast.person_id = person.id
WHERE birthdate IS NOT NULL
GROUP BY production_cast.production_id;

但是 IMDB 数据集非常庞大,需要 300 多秒才能完成。如果没有 GROUP BY 和 MIN,此查询将在 0.2 秒内运行:

SELECT production_cast.production_id FROM person
LEFT JOIN production_cast ON production_cast.person_id = person.id
WHERE birthdate IS NOT NULL;

数据库引擎是 MyIsam。 Mysql版本是5.7.2。我尝试在以下位置使用这些 BTREE 索引:

  • production_cast.production_id
  • person.birthdate
  • person.birthdate 和 person.id
  • production_cast.id 和 production_cast.production_id

explain 的简要输出是: 人物:范围, 索引: idx_Person_id_birthdate、idx_Person_id_birthdate、 额外:使用where;使用索引;使用临时的;使用文件排序

Production_cast: 参考, 索引: idx_Production_cast_person_id_production_id 额外:使用索引

person.id 和 production_cast.id 是主键索引。 production_cast.production_id 不是主键,但有索引。我可以做些什么来提高这个搜索查询的速度。

【问题讨论】:

  • explain select... 对上述查询说了什么?将其添加到问题中。
  • 请显示表格的布局。例如product_cast.id 是主键吗?
  • @AbhikChakraborty 解释的结果是:对于人: 键: 生日,行: 366741, Extra: '使用索引条件;使用 MRR;使用临时的;使用文件排序' 对于生产演员: possiblekeys: PRIMARY, person_id key: person_id 所有 ids 都是主键,生日有索引 b>
  • 你说数据库很大 => 有很多结果 => 一个根本无法滚动所有这些结果 => 为什么不使用分页器并限制结果呢? PS:尝试使用 subselect 摆脱 using filesort
  • 我不明白,当一个完美的 PostgreSQL 存在时,为什么有人会故意选择 MySQL

标签: mysql sql database


【解决方案1】:

您可以添加一些索引来加快数据检索。

开启production_cast

  • person_id
  • id

person:

  • id
  • birthdate

这样,数据库不需要检索所有数据,只需检索索引中的数据。此外,索引列的顺序将加快检索速度。您还应该将 person.birth_date 列别名为解析时间下降:

SELECT pc.id
,      MIN(p.birthdate)
FROM   person p
LEFT 
JOIN   production_cast pc
ON     pc.person_id = p.id
WHERE  p.birthdate IS NOT NULL
GROUP
BY     pc.id;

【讨论】:

  • 他肯定漏掉了一些重要的索引
  • 你提到的所有索引都存在。
  • @orcungumus:你是抄我的吗?您是如何找到这些索引的?它们完全如上吗?
  • 实际上,为了测试,我在开始时添加了所有组合,但目前在 production_cast: person.id, production_id, id 和 person: id,birthdate 和复合索引(birthdate, id) 存在。问题是它使用复合索引,但它继续进行文件排序
  • @PatrickHofman 它使用两个索引(为此+1),但它继续进行文件排序。所以仍然需要 190 秒。
【解决方案2】:

首先,LEFT JOIN 不是必需的,除非您关心不在任何制作演员阵容中的“人”。这似乎不太可能。因此,您的查询是:

SELECT p.id, MIN(birthdate)
FROM person p JOIN
     production_cast pc
     ON pc.person_id = p.id
WHERE p.birthdate IS NOT NULL
GROUP BY pc.id;

其次,如果production_cast.id 是主键并且person.id 是主键,则查询不能为给定的production_cast.id 生成重复值。因此,group by 不是必需的:

SELECT p.id, p.birthdate
FROM person p JOIN
     production_cast pc
     ON pc.person_id = p.id
WHERE p.birthdate IS NOT NULL;

我怀疑您在 production_cast 中有另一个表或另一个聚合键,但您的查询没有按照您认为的那样做。

【讨论】:

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