为什么带有InnoDB的MySQL在密钥存在时进行表扫描并选择检查70多行?

时间:2010-04-15 01:13:12

标签: mysql database performance optimization innodb

我正在解决查询性能问题。这是解释中的预期查询计划:

mysql> explain select * from table1 where tdcol between '2010-04-13 00:00' and '2010-04-14 03:16';
+----+-------------+--------------------+-------+---------------+--------------+---------+------+---------+-------------+
| id | select_type | table              | type  | possible_keys | key          | key_len | ref  | rows    | Extra       |
+----+-------------+--------------------+-------+---------------+--------------+---------+------+---------+-------------+
|  1 | SIMPLE      | table1             | range | tdcol         | tdcol        | 8       | NULL | 5437848 | Using where | 
+----+-------------+--------------------+-------+---------------+--------------+---------+------+---------+-------------+
1 row in set (0.00 sec)

这是有道理的,因为使用了名为tdcol(KEY tdcol (tdcol))的索引,并且应该从该查询中选择大约5M行。

但是,如果我只查询一分钟的数据,我们就会得到这个查询计划:

mysql> explain select * from table1 where tdcol between '2010-04-13 00:00' and '2010-04-14 03:17';
+----+-------------+--------------------+------+---------------+------+---------+------+-----------+-------------+
| id | select_type | table              | type | possible_keys | key  | key_len | ref  | rows      | Extra       |
+----+-------------+--------------------+------+---------------+------+---------+------+-----------+-------------+
|  1 | SIMPLE      | table1             | ALL  | tdcol         | NULL | NULL    | NULL | 381601300 | Using where | 
+----+-------------+--------------------+------+---------------+------+---------+------+-----------+-------------+
1 row in set (0.00 sec)

优化器认为扫描会更好,但要检查的行数超过70倍,所以我很难相信表扫描更好。

此外,'USE KEY tdcol'语法不会更改查询计划。

提前感谢您的帮助,我非常乐意提供更多信息/回答问题。

4 个答案:

答案 0 :(得分:3)

500万个索引探测器可能比读取所有3.5亿行(顺序磁盘读取)更昂贵(大量随机磁盘读取,可能更复杂的同步)。

这种情况可能是一个例外,因为大概时间戳的顺序大致与插入表中的顺序相匹配。但是,除非tdcol上的索引是“聚簇”索引(意味着数据库确保基础表中的顺序与tdcol中的顺序匹配),否则优化程序不太可能知道这一点。

如果没有订单关联信息,那么假设您想要的500万行大致均匀地分布在3.5亿行中是正确的,因此索引方法将涉及读取大部分或几乎全部的无论如何,在底层行中的页面(在这种情况下,扫描将比索引方法便宜得多,完全更少读取和顺序而不是随机读取)。

答案 1 :(得分:0)

MySQL的查询生成器在确定如何使用索引时有一个截止点。正如您已经正确识别的那样,MySQL已经确定表扫描将比使用索引更快,并且不会被它的决定所阻止。具有讽刺意味的是,当关键范围匹配超过表的三分之一时,它可能是正确的。那么为什么在这种情况下?

我没有答案,但我怀疑MySQL没有足够的内存来探索索引。我会查看服务器内存设置,特别是Innodb内存池和一些其他密钥存储池。

答案 2 :(得分:0)

您的数据分布情况如何?尝试在其上运行min(),avg(),max()以查看它的位置。 1分钟可能会对该范围中包含的信息量产生影响。

它也可以只是InnoDB的背景设置有几个因素,如页面大小,和像staticsan说的内存。您可能希望明确定义B + Tree索引。

答案 3 :(得分:0)

“所以我很难相信桌面扫描更好。”

真。 很难相信它。但优化器似乎没有。

我不会说你的“正确”而你的优化者是“正确的”。但优化者会像他们那样做,总而言之,他们的“智力”能力仍然被认为是相当有限的。

那就是说,您的数据库统计信息是否显示MAX值(对于此列)恰好等于“多一秒”值?

如果是这样,那么优化器可能已经断定所有行都满足上限,并且可能已经决定采用不同的方式,与必须得出结论的情况相比,“哦,肯定有一些行赢了” t也满足上限,所以我将使用索引来保证安全“。