表信息在下面,它在表中有近1000万行:
CREATE TABLE `t_user` (
`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'user id',
`user_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT 'user name',
`nick_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT 'nick name',
`portrait` varchar(128) DEFAULT '' COMMENT 'portrait url',
`password` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT 'user password',
`create_time` datetime NOT NULL,
`update_time` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uni_idx_un` (`user_name`)
) ENGINE=InnoDB AUTO_INCREMENT=10080960 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
在这里可以看到对这个sql select * from t_user where id >=10000 limit 5;
的解释:
我的问题是,为什么它需要扫描这么多行(近500万行),而id字段有索引?我认为它只需要扫描5行,因为它可以使用主索引跳过id < 10000
所在的行。
发布于 2022-10-20 13:06:37
MySQL不会扫描500万行。
首先,所显示的数字只是一个估计,例如,一个非常粗略的猜测,有多少行可以通过这个索引选择被扫描。它的目的是帮助优化器做出决定。
此外,这一限制的影响实际上根本没有反映在这一数字中。它显示了它将没有限制的值(但使用该索引)。尝试更改限制的值,行估计将不会调整(假设执行计划保持不变)。
估计值已经在不同的步骤和不同的原因中计算出来,而围绕限值的决策是在不同的地方进行的。虽然在您的具体案例中,只需说明最多扫描了多少行(可能较少,所以即使在最简单的情况下也存在一些不确定性),但在大多数情况下,实际上并非如此。
例如,尝试使用where nick_name = 'yates'
或where id >= 10000 and nick_name = 'yates'
的表。如果添加了一个limit 1
,那么更正应该是什么?它可以介于“减少到1行”和“根本没有效果”之间。
因此,没有人重新计算估计行,这是一个非常粗略的估计,首先,包括估计的影响,限制,这也将主要是猜测。为了明确起见,MySQL当然知道限制,如果添加限制,可以选择不同的索引/执行计划。它只是不会重新计算这个值。
要查看为查询扫描的实际行,可以使用例如侧写器 (查看列rows_examined
),或者从MySQL 8.0.18开始使用,,它将运行查询并显示实际读取的行(以及所用的时间)。
https://stackoverflow.com/questions/74135112
复制相似问题