MySQL使用不同的索引,取决于使用ORDER BY查询的限制值

时间:2015-03-18 15:08:44

标签: mysql sql-order-by

这对我来说很奇怪: 一个表'ACTIVITIES',ACTIVITY_DATE有一个索引。具有不同LIMIT值的完全相同的查询会导致不同的执行计划。

这是:

mysql> explain select * from ACTIVITIES order by ACTIVITY_DATE desc limit 20
    -> ;
+----+-------------+------------+-------+---------------+-------------+---------+------+------+-------+
| id | select_type | table      | type  | possible_keys | key         | key_len | ref  | rows | Extra |
+----+-------------+------------+-------+---------------+-------------+---------+------+------+-------+
|  1 | SIMPLE      | ACTIVITIES | index | NULL          | ACTI_DATE_I | 4       | NULL |   20 |       |
+----+-------------+------------+-------+---------------+-------------+---------+------+------+-------+
1 row in set (0.00 sec)

mysql> explain select * from ACTIVITIES order by ACTIVITY_DATE desc limit 150
    -> ;
+----+-------------+------------+------+---------------+------+---------+------+-------+----------------+
| id | select_type | table      | type | possible_keys | key  | key_len | ref  | rows  | Extra          |
+----+-------------+------------+------+---------------+------+---------+------+-------+----------------+
|  1 | SIMPLE      | ACTIVITIES | ALL  | NULL          | NULL | NULL    | NULL | 10629 | Using filesort |
+----+-------------+------------+------+---------------+------+---------+------+-------+----------------+
1 row in set (0.00 sec)

为什么我限制150它不使用索引?我的意思是,扫描150行似乎比扫描10629行更快,对吗?

修改

查询使用索引直到“limit 96”并在“limit 97”处启动filesort。 该表没有任何特定内容,即使不是外键,这里是完整的创建表:

mysql> show create table ACTIVITIES\G
*************************** 1. row ***************************
       Table: ACTIVITIES
Create Table: CREATE TABLE `ACTIVITIES` (
  `ACTIVITY_ID` int(11) NOT NULL AUTO_INCREMENT,
  `ACTIVITY_DATE` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `USER_KEY` varchar(50) NOT NULL,
  `ITEM_KEY` varchar(50) NOT NULL,
  `ACTIVITY_TYPE` varchar(1) NOT NULL,
  `EXTRA` varchar(500) DEFAULT NULL,
  `IS_VISIBLE` varchar(1) NOT NULL DEFAULT 'Y',
  PRIMARY KEY (`ACTIVITY_ID`),
  KEY `ACTI_USER_I` (`USER_KEY`,`ACTIVITY_DATE`),
  KEY `ACTIVITY_ITEM_I` (`ITEM_KEY`,`ACTIVITY_DATE`),
  KEY `ACTI_ITEM_TYPE_I` (`ITEM_KEY`,`ACTIVITY_TYPE`,`ACTIVITY_DATE`),
  KEY `ACTI_DATE_I` (`ACTIVITY_DATE`)
) ENGINE=InnoDB AUTO_INCREMENT=10091 DEFAULT CHARSET=utf8 COMMENT='Logs    activity'
1 row in set (0.00 sec)

mysql> 

我还试图运行“分析表活动”,但这没有改变。

1 个答案:

答案 0 :(得分:0)

事情的发展方向。请耐心等一下......

优化器想要使用INDEX,在本例中为ACTI_DATE_I。但如果速度较慢,它不想使用它。

计划A:使用索引。

  1. 最后到达BTree结构化索引(因为DESC)
  2. 向后扫描
  3. 对于索引中的每一行,查找数据中的相应行。注意:索引具有(ACTIVITY_DATE,ACTIVITY_ID),因为PRIMARY KEY隐式附加到任何辅助键。进入"数据"使用PK(ACTIVITY_ID)是另一个BTree查找,可能是随机的。因此,它可能很慢。 (但在你的情况下不是很慢。)
  4. 在LIMIT行之后停止。
  5. 计划B:忽略表格

    1. 扫描表格,构建一个tmp表格。 (可能是在记忆中。)
    2. 对tmp表进行排序
    3. 剥掉LIMIT行。
    4. 在你的情况下(10K的96-1%),它选择了表扫描是令人惊讶的。通常,截止值约为表中行数的10%-30%。

      ANALYZE TABLE 导致重新计算统计信息,可以确信它与其他计划一起使用。

      您使用的是哪个版本的MySQL? (不,我不知道这方面有任何变化。)

      您可以尝试的一件事:OPTIMIZE TABLE ACTIVITIES;这将重建表,从而重新打包块并导致潜在不同的统计信息。如果这有帮助,我想知道 - 因为我通常会说"优化表是没用的"。