1

我有这张桌子:

CREATE TABLE IF NOT EXISTS `test1_nopart` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `idAccount` int(10) unsigned NOT NULL,
  `data` mediumint(8) unsigned NOT NULL,
  `date` date NOT NULL,
  PRIMARY KEY (`id`),
  KEY `date` (`date`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

我用 10 000 000 行填充此表。按日期重新分区是同质的

EXPLAIN SELECT * FROM `test1_nopart` WHERE date = "2014-03-04" 

这是结果

id  select_type   table        type     possible_keys   key     key_len     ref     rows        Extra
1   SIMPLE     test1_nopart     ALL     NULL            NULL    NULL        NULL    7875981     Using where

=> 没有解释 3.6 秒,结果为 3000 行(大约)

如您所见,未使用索引,并且它不是 possible_keys 列的一部分!

具有覆盖索引方式的相同请求

EXPLAIN SELECT date FROM `test1_nopart` WHERE date = "2014-03-04"

结果:

id  select_type     table      type     possible_keys   key     key_len     ref     rows        Extra
1   SIMPLE       test1_nopart   index   NULL            date       3        NULL    7875981     Using where; Using index

=> 没有解释 2.8 秒,结果为 3000 行(大约)

为什么 MySQL 不能正确使用这个索引(日期)???

信息: - VM Server(我们的开发环境,我不知道硬件组成是什么) - MySQL 5.5.8

SHOW INDEX FROM test1_nopart

结果:

Table   Non_unique  Key_name    Seq_in_index    Column_name     Collation   Cardinality     Sub_part    Packed  Null    Index_type  Comment     Index_comment
test1_nopart    0   PRIMARY     1   id  A   7875981     NULL    NULL        BTREE        
test1_nopart    1   date    1   date    A   6077    NULL    NULL        BTREE        
  • 对于日期 2014-03-04 => 3134 行
  • 总计(汇总)=> 7 875 488
  • 表中有 2556 个不同的“日期”值
4

4 回答 4

1

MySQL 查询优化器发现日期索引的索引遍历包括对聚集索引的深入了解(内部称为gen_clust_index)。鉴于此,MySQL 查询优化器认为在第一个查询中执行全表扫描和在第二个查询中执行全索引扫描更容易。

您可能还需要查看索引的基数以及每个不同值有多少行。

执行以下操作:

SELECT COUNT(1) datecount,`date` FROM test1_nopart GROUP BY `date` WITH ROLLUP;

根据您的评论,您将获得 6077 个不同的行。您还说大约有 10,000,000 行。改为运行此查询:

SELECT COUNT(1) datecount FROM test1_nopart WHERE `date` = '2014-03-14';

请注意计数和总数。

10,000,000 的 5% 是 500,000

如果日期为 '2014-03-14' 的行数超过 500,000 行,那么 MySQL 将永远不会为该特定值正确使用索引。

我不信任SHOW INDEXES FROM test1_nopart;,因为该表是 InnoDB。MyISAM 将显示确切的数字。InnoDB 根据 Dives into the Index 生成数字。

如果任何日期的 datecount 超过总行数的 5%,MySQL 查询优化器就会举手进行全盘扫描。

更新

好的,5% 的经验法则是不可能的。尝试通过创建不同的覆盖索引来欺骗 MySQL 查询优化器:

ALTER TABLE test1_nopart ADD INDEX date_id_ndx (`date`,id);

并再次尝试您的查询。

于 2011-12-29T17:26:13.370 回答
0

这是我的想法。

在第一种情况下,当我们尝试data通过MySQL 获取时,由于基数非常低,因此date不使用索引。date优化器使用以下内容: - 二级索引 - 聚集以访问行 - 表以获取数据。

在第二种情况下,当我们尝试使用索引更容易通过表时,因为 MySQL 也可以从索引中检索选择的数据(我的意思是 MySQL 可以只扫描索引而不是整个表来获取相同的数据)datedate使用以下内容: - 二级索引

于 2011-12-29T18:47:46.663 回答
0

这不是基数问题。

我做了很多测试,我又发了一篇文章来描述这个问题。

https://stackoverflow.com/questions/8679940/primary-key-index-with-a-datetime-as-first-part-of-the-compound-key-is-never-use

仅当第一个键是日期时间时才会出现问题...

于 2011-12-30T13:36:41.803 回答
0

只是一种预感——也许它与这个词有关date

尝试向 MySQL 提供一些您想要使用该字段的提示,而不是保留字:

SELECT date FROM `test1_nopart` WHERE `test1_nopart`.`date` = "2014-03-04"
于 2011-12-29T17:17:50.313 回答