【问题标题】:Very slow MySQL LeftJoin on AWS RDS, but very quick elsewhereAWS RDS 上的 MySQL LeftJoin 非常慢,但在其他地方非常快
【发布时间】:2020-07-14 02:17:44
【问题描述】:

PROD 中的 MySQL 通过 AWS RDS(Aurora,db.t3.small)运行。全面的资源利用率处于令人满意的水平。

如果我执行以下 SELECT,它几乎是瞬时的:

 SELECT SQL_CALC_FOUND_ROWS `submissions`.*
 FROM `cmsb_submissions` as `submissions`
 WHERE (status = '4') 
 LIMIT 15

如果我添加 LEFTJOIN,则需要 15 秒以上:

SELECT SQL_CALC_FOUND_ROWS `submissions`.*,
`explorer_points_earning`.`num` AS `explorer_points_earning.num`,
`explorer_points_earning`.`createdDate` AS `explorer_points_earning.createdDate`,
`explorer_points_earning`.`createdByUserNum` AS `explorer_points_earning.createdByUserNum`,
`explorer_points_earning`.`updatedDate` AS `explorer_points_earning.updatedDate`,
`explorer_points_earning`.`updatedByUserNum` AS `explorer_points_earning.updatedByUserNum`,
`explorer_points_earning`.`user` AS `explorer_points_earning.user`,
`explorer_points_earning`.`points_earned` AS `explorer_points_earning.points_earned`,
`explorer_points_earning`.`for_trail` AS `explorer_points_earning.for_trail`
FROM `cmsb_submissions` as `submissions`
LEFT JOIN `cmsb_explorer_points_earning` AS `explorer_points_earning` 
     ON submissions.num = explorer_points_earning.for_trail
    AND explorer_points_earning.user = 7
WHERE (status = '4') 
 LIMIT 15

两个表都不大:

explorer_points_earning = 17,000 records
submissions = 1,000 records 

并且存在以下索引:

SHOW INDEX FROM cmsb_explorer_points_earning;

'cmsb_explorer_points_earning', '0', 'PRIMARY', '1', 'num', 'A', '17155', NULL, NULL, '', 'BTREE', '', ''
'cmsb_explorer_points_earning', '1', '_auto_for_trail', '1', 'for_trail', 'A', '2450', '16', NULL, 'YES', 'BTREE', '', ''
'cmsb_explorer_points_earning', '1', '_auto_user', '1', 'user', 'A', '3431', '16', NULL, 'YES', 'BTREE', '', ''

所以,无论如何,这都不是一个大问题。

完全相同的查询(使用 LEFTJOIN),在我的本地开发服务器上使用完全相同的数据库转储(资源较少)是即时的。

我确信这不是 RDS“资源”问题,因为我将实例加倍为 t3.medium 并且没有任何区别。

这让我认为这是索引错误或某些 RDS 特定配置错误。

解释:

在 RDS 上:

'1', 'SIMPLE', 'submissions', 'ALL', NULL, NULL, NULL, NULL, '1100', 'Using where'
'1', 'SIMPLE', 'explorer_points_earning', 'ALL', '_auto_for_trail', NULL, NULL, NULL, '17155', 'Range checked for each record (index map: 0x2)'

在开发中:

'1', 'SIMPLE', 'submissions', NULL, 'ALL', NULL, NULL, NULL, NULL, '1064', '100.00', NULL
'1', 'SIMPLE', 'explorer_points_earning', NULL, 'ALL', '_auto_user,_auto_for_trail', NULL, NULL, NULL, '17082', '100.00', 'Using where; Using join buffer (hash join)'

显着的区别是 RDS 仅将“auto_for_trail”作为“可能的键”,而 DEV 具有两个字段,_auto_user 和 _auto_for_trail。 RDS 使用嵌套循环,DEV 使用哈希连接。

毫无疑问,我可以提供更多信息来帮助调试它,但我不确定是什么,所以请告诉我还有什么可以帮助的。

任何帮助,非常感谢,

谢谢

-- 额外信息--

SHOW CREATE TABLE cmsb_explorer_points_earning;

RDS

CREATE TABLE 
`cmsb_explorer_points_earning` (
    `num` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `createdDate` datetime NOT NULL, 
    `createdByUserNum` int(10) unsigned NOT NULL, 
    `updatedDate` datetime NOT NULL, 
    `updatedByUserNum` int(10) unsigned NOT NULL, 
    `user` mediumtext COLLATE utf8mb4_unicode_ci, 
    `points_earned` mediumtext COLLATE utf8mb4_unicode_ci, 
    `for_trail` mediumtext COLLATE utf8mb4_unicode_ci, 
    PRIMARY KEY (`num`), 
    KEY `_auto_for_trail` (`for_trail`(16)), KEY `_auto_user` (`user`(16))
) ENGINE=InnoDB AUTO_INCREMENT=17191 DEFAULT 
CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci'

MySQL 版本:5.6.10

开发/本地

CREATE TABLE         
`cmsb_explorer_points_earning` (
    `num` int unsigned NOT NULL AUTO_INCREMENT, 
    `createdDate` datetime NOT NULL, 
    `createdByUserNum` int unsigned NOT NULL, 
    `updatedDate` datetime NOT NULL, 
    `updatedByUserNum` int unsigned NOT NULL, 
    `user` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, 
    `points_earned` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, 
    `for_trail` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, 
    PRIMARY KEY (`num`), 
    KEY `_auto_user` (`user`(16)), KEY `_auto_for_trail` (`for_trail`(16))
) ENGINE=InnoDB AUTO_INCREMENT=17181 DEFAULT 
CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci'

MySQL 版本:8.0.20-0ubuntu0.20.04.1

【问题讨论】:

  • 您的第二个查询丢失.....第一个表选择条件的 WHERE (status = '4')。
  • 请提供SHOW CREATE TABLE(如果Wilson 的评论不够)。
  • 这两个 MySQL 是什么版本?
  • @WilsonHauck - 抱歉,这只是帖子中的一个错误。它确实包含 WHERE 查询;我只是没有粘贴完整的查询。会更新。
  • @RickJames - 我已经在帖子中添加了额外的信息。具有潜在意义的是,RDS 是 v 5.6.10,而 DEV 是 8.0.2。

标签: mysql amazon-rds database-indexes mysql-slow-query-log


【解决方案1】:

添加这个:

INDEX(user, for_trail)

此时,INDEX(user) 是多余的,应该被删除。

如果“用户”是用户名,您确实不需要需要MEDIUMTEXT(最大为 16M 字节)。您也不需要TEXT(最多 64K 字节)。把它改成像VARCHAR(100)这样文明的东西。

如果可行,其他 MEDIUMTEXTs 也一样。届时,我建议的索引将起作用。

另一种解决方法是按照您的尝试使用“前缀”:

KEY `_auto_for_trail` (`for_trail`(16)),
KEY `_auto_user` (`user`(16))

但是,你已经发现那是相当没用的。

此外,没有ORDER BYLIMIT 会使15 行的选择变得不可预测。

【讨论】:

  • 我应该如何/在哪里添加它?如果我运行 ALTER TABLE cmsb_explorer_points_earning ADD INDEX(user, for_trail);它返回错误代码:1170. BLOB/TEXT 列“用户”在没有密钥长度的密钥规范中使用
  • @user1513196 我更新了我的答案。 (好吧,对于“为什么一个比另一个快”,我仍然没有答案。但是,我希望我的建议将使 两个 服务器“快”。如果没有,我会看看更深。)
  • "user" 和 "for_trail" 都只是数字(链接到其他表中的主键)。将这些从 MEDIUMTEXT 更改为 INT(11) 使语句从 17 秒变为 0.03 秒!谢谢:-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-30
  • 2022-06-14
  • 1970-01-01
  • 2018-03-16
  • 2013-06-19
  • 2015-06-11
  • 2015-09-02
相关资源
最近更新 更多