当表具有其他字段时,MySQL不使用DATETIME索引

我需要一些帮助来解决这个问题.我试图让Mysql在DATETIME字段上使用索引.

如果表中还有其他(未使用)字段,则Mysql决定不使用索引.请考虑以下两种情况:

一个带有2个字段的简单表可以正常工作:

DROP TABLE IF EXISTS datetime_index_test;
CREATE TABLE  datetime_index_test (
id INT UNSIGNED NOT NULL AUTO_INCREMENT ,
created DATETIME NOT NULL ,
PRIMARY KEY (id) ,
INDEX (created)
) ENGINE = InnoDB ;

INSERT INTO datetime_index_test (created) VALUES
('2011-04-06 00:00:00'),
('2011-04-06 01:00:00'),
('2011-04-06 02:00:00'),
('2011-04-06 03:00:00'),
('2011-04-06 04:00:00'),
('2011-04-06 05:00:00'),
('2011-04-06 06:00:00'),
('2011-04-06 00:00:00');

EXPLAIN SELECT * FROM datetime_index_test
WHERE created <= '2011-04-06 04:00:00';

+----+-------------+---------------------+-------+---------------+---------+---------+------+------+--------------------------+
| id | select_type | table               | type  | possible_keys | key     | key_len | ref  | rows | Extra                    |
+----+-------------+---------------------+-------+---------------+---------+---------+------+------+--------------------------+
|  1 | SIMPLE      | datetime_index_test | range | created       | created | 4       | NULL |    4 | Using where; Using index |
+----+-------------+---------------------+-------+---------------+---------+---------+------+------+--------------------------+

具有3个字段的简单表不能正常工作:

DROP TABLE IF EXISTS datetime_index_test;
CREATE TABLE  datetime_index_test (
id INT UNSIGNED NOT NULL AUTO_INCREMENT ,
created DATETIME NOT NULL ,
user int(10) unsigned DEFAULT 0,
PRIMARY KEY (id) ,
INDEX (created)
) ENGINE = InnoDB ;

INSERT INTO datetime_index_test (created) VALUES
('2011-04-06 00:00:00'),
('2011-04-06 01:00:00'),
('2011-04-06 02:00:00'),
('2011-04-06 03:00:00'),
('2011-04-06 04:00:00'),
('2011-04-06 05:00:00'),
('2011-04-06 06:00:00'),
('2011-04-06 00:00:00');

EXPLAIN SELECT * FROM datetime_index_test
WHERE created <= '2011-04-06 04:00:00';

+----+-------------+---------------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table               | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+---------------------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | datetime_index_test | ALL  | created       | NULL | NULL    | NULL |    8 | Using where |
+----+-------------+---------------------+------+---------------+------+---------+------+------+-------------+

最后,我的问题;谁能向我解释为什么Mysql决定不使用索引?

解决方法:

这是由于我所说的基于关键人群(元组基数)的5%规则.

如果您在存在偏基数的表中建立索引,则MySQL Query Optimizer将始终选择阻力最小的路径.

示例:如果表具有性别列,则基数为2,M和F.

您如何索引这样的性别列?您将获得两个巨大的链接列表.

如果将一百万行加载到带有性别列的表中,则可能会得到50%M和50%F.

如果键组合的基数(如我所说的键填充)的基数大于表总数的5%,则在查询优化期间索引将变得无用.

现在,关于您的示例,为什么要使用两个不同的EXPLAIN计划?我的猜测是将MySQL Query Optimizer和InnoDB作为标记团队.

在第一个CREATE TABLE中,表和索引虽然很小,但它们大约具有相同的大小,因此它通过执行索引扫描而不是全表扫描来决定使用索引.请记住,非唯一索引在其索引条目中包含每一行的内部主键(RowID),因此使索引的大小几乎与表本身相同.

在第二个CREATE TABLE中,由于引入了另一列user,您现在使Query Optimizer看到了一种完全不同的方案:该表现在比索引大.因此,查询优化器对如何使用可用索引的解释变得更加严格.达到了我之前提到的5%规则.该规则失败了,查询优化器决定支持全表扫描.

上一篇:用于尝试编译器优化的Python库


下一篇:加速将rtf转换为纯文本