我想知道为什么一个简单的选择 LIMIT 1
子句(不可否认,在一个包含大量行和索引的非常臃肿的表上)有时在awsrds aurora示例上执行需要30多秒(有时甚至2分钟)。这是一个writer示例。
对于来自客户机的第一个查询,它似乎只发生在查看成千上万行的特定select上,而且有时也会发生。
查询的格式为:
SELECT some_table.col1, some_table.col2, some_table.col3, some_table.col4,
MAX(some_table.col2) AS SomeValue
FROM some_table
WHERE some_table.col3=123456 LIMIT 1;
和“解释”输出:
+----+-------------+---------------+------+---------------+---------+---------+-------+--------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------------+------+---------------+---------+---------+-------+--------+-------+
| 1 | SIMPLE | some_table | ref | col1 | col1 | 4 | const | 268202 | NULL |
+----+-------------+---------------+------+---------------+---------+---------+-------+--------+-------+
我设法重现了这个问题,并在phpmyadmin中捕获了查询的概要文件。phpmyadmin记录查询的执行时间为30.1秒,但探查器显示执行本身的时间不到一秒:
所以看起来执行本身并不花费很多时间;是什么导致了这个延迟问题?我还发现了rds performance insights中记录的相同查询:
对于一系列相同或相似的查询中的第一个查询,似乎会发生这种情况。可能是缓存问题吗?我试过跑步 RESET QUERY CACHE;
试图重现潜伏期但没有成功。如果有帮助的话,我很乐意提供更多关于基础设施的信息。
更多信息
SHOW VARIABLES LIKE 'query_cache%';
SHOW GLOBAL STATUS LIKE 'Qc%';
检查并发送的行(来自性能分析):SHOW CREATE TABLE
输出:
CREATE TABLE `some_table` (
`col1` int(10) unsigned NOT NULL AUTO_INCREMENT,
`col2` int(10) unsigned NOT NULL DEFAULT '0',
`col3` int(10) unsigned NOT NULL DEFAULT '0',
`col4` int(10) unsigned NOT NULL DEFAULT '0',
`col5` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL,
`col6` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`col7` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`col1`),
KEY `col2` (`col2`),
KEY `col3` (`col3`),
KEY `col4` (`col4`),
KEY `col6` (`col6`),
KEY `col7` (`col7`)
) ENGINE=InnoDB AUTO_INCREMENT=123456789 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
2条答案
按热度按时间zaqlnxep1#
可能的解释是:
查询执行延迟,因为它正在等待锁。甚至像这样的只读查询
SELECT
可能需要等待元数据锁。查询必须检查数十万行,从存储中读取这些行需要时间。极光应该有快速存储,但它不能是零成本。
aurora示例上的系统负载太高,因为它正在与正在运行的其他查询竞争。
aurora示例上的系统负载太高,因为主机由其他amazon客户拥有的其他aurora示例共享。这种情况有时被称为“吵闹的邻居”,你几乎无法阻止它。亚马逊自动为同一硬件上的不同客户提供虚拟机。
将结果集传输到客户端需要很长时间。既然你用了
LIMIT 1
,这一行必须是巨大的,需要30秒,否则你的客户必须在一个非常缓慢的网络。第一次运行查询时,查询缓存不相关。随后执行同一查询的速度会更快,直到从缓存中逐出结果之后的某个时间,或者如果该表中的任何数据被更新,则会强制从查询缓存中逐出针对该表的所有查询的结果。
bvjxkvbb2#
看来你对
LIMIT
函数在这种情况下不太正确。如果你运行一个简单的函数
SELECT * FROM tablea LIMIT 1;
然后数据库会显示它遇到的第一行,并在那里终止,给您一个快速返回。但是,在上面的示例中,您有一个聚合函数和一个where子句。因此,为了让数据库返回第一行,它必须首先返回整个数据集,然后计算出第一行是什么。
你可以在前面的问题中阅读更多关于这方面的内容;https://dba.stackexchange.com/a/62444
如果你运行同样的查询
limit 1
最后,您可能会发现返回结果所需的时间大致相同。正如您在评论中提到的那样,最好查看模式并找出如何修改此查询以提高效率。