【问题标题】:MySQL JOIN very slow for no apparent reasonMySQL JOIN 很慢,没有明显的原因
【发布时间】:2020-07-09 03:37:12
【问题描述】:

MySQL 版本 8.0.17:

SELECT b.ColB
FROM Table2 b
JOIN Table1 a ON a.ColA = b.ColA
WHERE b.ColB = 1234 -- some number

使用JOIN,此查询大约需要 2 秒才能运行,没有 JOIN 几乎是即时的。这只是一个小例子,实际情况需要WHERE 条件来覆盖多个值(例如WHERE b.ColB BETWEEN 1000 AND 2000)——这需要很长时间...

Table1 的结构(为简洁起见,删除了不相关的列和索引):

CREATE TABLE `Table1` (
  `ColA` int(11) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`ColA`)
) ENGINE=InnoDB AUTO_INCREMENT=138221783 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

Table2 的结构(为简洁起见,删除了不相关的列和索引):

CREATE TABLE `Table2` (
  `ColA` int(11) NOT NULL,
  `ColB` int(11) NOT NULL,
  PRIMARY KEY (`ColA`,`ColB`),
  KEY `FK_Table2_Table1_idx` (`ColA`),
  KEY `FK_Table2_Table3_idx` (`ColB`),
  CONSTRAINT `FK_Table2_Table1` FOREIGN KEY (`ColA`) REFERENCES `Table1` (`ColA`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

这是该查询解释的 CSV:

id,select_type,table,partitions,type,possible_keys,key,key_len,ref,rows,filtered,Extra
1,SIMPLE,rc,NULL,ref,"PRIMARY,FK_Table2_Table1_idx,FK_Table2_Table3_idx",FK_Table2_Table3_idx,4,const,607,100.00,"Using index"
1,SIMPLE,r,NULL,eq_ref,PRIMARY,PRIMARY,4,Table2.ColA,1,100.00,"Using index"

运行此SELECT COUNT(*) FROM Table1 的一些额外信息耗时 8.735 秒并返回 1947948。

运行 SELECT COUNT(*) FROM Table2 耗时 168.422 秒,返回 19486319。

为什么JOIN 导致查询运行如此缓慢?

【问题讨论】:

  • 你告诉 mysql 比较两个大标签并检查是否有任何行适合在一起。如果您的查询使用正确的索引,请首先检查 EXPLAIN。第二。通过直接在 tabke b 上使用 where 子句来减少行数,以便只匹配几行
  • 解释显示正确的索引,我如何将 where 移动到表 2?我将 EXPLAIN 的结果添加到问题中。
  • 嘿....为什么Table3在里面解释???
  • 因为它可以成为ina index的候选对象
  • 我认为它使用了错误的索引!

标签: mysql query-optimization mysql-8.0


【解决方案1】:

如果唯一的索引是PRIMARY KEY(colA, colB) 并且WHERE 子句正在测试colB=constant,那么没有可用的索引。

如果这是一个多对多映射表,您需要添加 INDEX(colB, colA) 以允许有效地从 B 到 A。

【讨论】:

  • 刚才ColB上有一个索引,叫FK_Table2_Table3_idx
  • @AviadP。 - b.ColB = 1234 有多少行?输出有那么多行吗?
【解决方案2】:

要减少必须连接的行数,请尽可能减少行数。

为了你的孩子

使用

SELECT b.ColB
FROM (SELECT * FROM Table2 WHERE ColB = 1234) b
JOIN Table1 a ON a.ColA = b.ColA

您必须仅使用您实际需要的列,而不是 SELECT * FROM Table2。

【讨论】:

  • 除非派生表有GROUP BYLIMIT,否则重新表述没有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-15
  • 1970-01-01
  • 2012-06-26
  • 1970-01-01
  • 2016-12-04
相关资源
最近更新 更多