为什么mysql中的select查询速度如此之慢?

为什么mysql中的select查询速度如此之慢?,mysql,sql,Mysql,Sql,表模式 数据库引擎是MyISAM 提交(约500000000行) id(int)-PK(索引) 项目标识(int)-FK[项目->标识](索引) 提交者id-FK[用户->id](索引) 项目(约3200万行) id(int)-PK(索引) 用户(约12000000行) id-PK(索引) 解释 SELECT COUNT(*) FROM commits WHERE committer_id = 30351173 上述查询在10秒内完成。 SELECT project_id , CO

表模式

数据库引擎是MyISAM

提交(约500000000行)
id(int)-PK(索引)
项目标识(int)-FK[项目->标识](索引)
提交者id-FK[用户->id](索引)

项目(约3200万行)
id(int)-PK(索引)

用户(约12000000行)
id-PK(索引)


解释

SELECT COUNT(*) 
FROM commits 
WHERE committer_id = 30351173
上述查询在10秒内完成。

SELECT project_id , COUNT(*) as commit_count
FROM commits
WHERE committer_id = 30351173
GROUP BY project_id
但是,上述查询未在2小时内完成(7200秒)

提交中的
项目id
是完整的索引列,但速度太慢

为什么会这样

Q)如何加快第二次查询的速度?


附加的

SELECT project_id , COUNT(*) AS commit_count
FROM commits
WHERE committer_id = 1891264
GROUP BY project_id
我查询另一个
committer\u id
是否已完成15秒。

SELECT project_id , COUNT(*) as commit_count
FROM commits
WHERE committer_id = 30351173
GROUP BY project_id
附加-2

EXPLAIN SELECT COUNT(*) FROM commits WHERE committer_id = 30351173
输出

输出

这是因为

分组

声明

SQL Server必须检查表中的每一行

项目id上的索引可能会解决此问题

alter table提交添加索引(提交者id)

您应该尝试一种覆盖索引,如

为什么? 您的查询:

  • 从表中选择
    project\u id
  • 选择使用
    committer\u id
  • 使用
    project\u id
通过在常量
where
子句(此处为
committer\u id
)位于第一个位置的位置创建索引,您可以让MySQL在访问表之前快速将涉及的记录归零。一旦有了这些记录,MySQL就可以开始工作了但是如果索引中还有用于分组的信息,即
project\u id
,MySQL甚至可以在访问表之前开始分组数据。最后,如果all索引上也存在其他信息(这里已经完成了,因为它与
WHERE
使用的信息相同),MySQL根本不需要访问该表。按此顺序提供此信息的索引是此查询的覆盖索引

当然,这是更有利的,相对于完整表行,您使用的数据越小;显然,如果您有一个100 GB的表和一个75 GB的索引,那么性能增益很小。如果您有一个100 GB的表和1 GB的索引,您将获得一个巨大的胜利。特别是当1GB索引上的查询基数较低时(例如,提交者只负责1%的数据)。然后,您将读取10MB的数据,而不是100GB的数据,并且您不会相信性能的提高

获得索引后,您将执行以下操作:

SELECT project_id , COUNT(1) AS commit_count
    FROM commits
    WHERE committer_id = 1891264
GROUP BY project_id
这应该只在索引上运行

我说,试试看,因为维护索引也要付出代价。这种情况很可能是您加快了这个SELECT查询的速度,代价是降低了插入和更新的速度,因为它们需要管理索引和表

顺便说一句,通过使用COUNT(1),查询将不会显示在
grep
搜索中,从而允许关注带有重要星号的查询


此外,当您进行此类测试时,请记住执行以下操作:

  • 对慢速id的测试
  • 在不同的id上进行测试
  • 使用稍有不同的查询(例如,添加AS..alias)在slow_id上再次测试
第三个测试的原因是,在运行第一个查询时,MySQL还将加载池中的数据(如果使用InnoDB,则不加载),以及RAM中的数据,因此第二个查询可能会更快,因为池、内存和任何I/O缓存都已启动。如果是这样的话,第三个查询也会运行得更快,当然,如果它可以与第二个查询相媲美的话,“这个查询很慢”的问题将被揭示为一个工件

但由于查询是缓存的,所以您希望再次获取相同的数据,而不是从缓存中提取结果。因此,第三个查询需要稍有不同才能丢弃缓存。否则,您将看到一个非常快速的查询,而实际上它不是


(1) 这是如果您运行快速测试。否则,性能测试要比这复杂得多;Percona博客上有几篇关于这个主题的文章。

真正重要的专栏是
committer\u id
。有索引吗?你把条件加进去了!为提交者id添加一个索引,它应该会加快速度。此外,相对于
COUNT(*)
,您还可以计算每一行的唯一标识符,如果存在的话-认为您有
id
?是的<代码>提交者id
是索引(BTREE)列。外键用户->idPut
解释
之前选择
并将输出粘贴到此处。谢谢。OP使用的是MySQL,而不是SQL Server。无论如何,
WHERE
子句很可能是此处的关键部分,这意味着
committer\u id
列上的索引对您的答复至关重要。我会尽力让你知道结果。
SELECT project_id , COUNT(1) AS commit_count
    FROM commits
    WHERE committer_id = 1891264
GROUP BY project_id