为什么添加新列后MySQL查询执行计划发生变化?

为什么添加新列后MySQL查询执行计划发生变化?,mysql,indexing,sql-execution-plan,Mysql,Indexing,Sql Execution Plan,我有一个表格和一些数据如下: -- MySQL dump 10.13 Distrib 5.7.17, for macos10.12 (x86_64) -- -- Host: localhost Database: testmysql -- ------------------------------------------------------ -- Server version 5.7.17-log -- -- Table structure for table `t_str

我有一个表格和一些数据如下:

-- MySQL dump 10.13  Distrib 5.7.17, for macos10.12 (x86_64)
--
-- Host: localhost    Database: testmysql
-- ------------------------------------------------------
-- Server version   5.7.17-log


--
-- Table structure for table `t_strange_index`
--

DROP TABLE IF EXISTS `t_strange_index`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;

CREATE TABLE `t_strange_index` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `status` tinyint(4) NOT NULL,
  `create_time` bigint(20) NOT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  KEY `idx_time_status` (`create_time`,`status`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=21
       DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=COMPACT;

/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `t_strange_index`
--

LOCK TABLES `t_strange_index` WRITE;
/*!40000 ALTER TABLE `t_strange_index` DISABLE KEYS */;
INSERT INTO `t_strange_index` VALUES
        (1,1,1532745820825),(2,1,1532745864183),(3,1,1532745895207),
        (4,1,1532746773225),(5,1,1532746773225),(6,1,1532746773225),
        (7,1,1532746822078),(8,1,1532746822078),(9,1,1532746822078),
        (10,1,1532746979836),(11,1,1532746979836),(12,1,1532746979836),
        (13,9,1532763766641),(14,10,1532764510924),(15,10,1532765436500),
        (16,20,1532777350303),(17,9,1532777818806),(18,10,1532782628840),
        (19,10,1532782711973),(20,10,1532784164740);
/*!40000 ALTER TABLE `t_strange_index` ENABLE KEYS */;
UNLOCK TABLES;
然后获取此SQL的查询执行计划:

explain select * from t_strange_index
      where create_time >= 1532746822078
        and create_time <= 1532746979836
        and status = 1;
但在我添加了一个新列之后

alter table t_strange_index add column `new column` bigint(20) NOT NULL default 123;
执行计划变更:

 id | select_type | table           | partitions | type | possible_keys   | key  | key_len | ref  | rows | filtered | Extra       
  1 | SIMPLE      | t_strange_index | NULL       | ALL  | idx_time_status | NULL | NULL    | NULL |   20 |     5.00 | Using where 
它不再使用索引

谁能告诉我为什么会这样?谢谢。

封面索引

你应该注意到你原来的解释额外使用索引。这是覆盖指数的指标

覆盖索引是包含查询所需的所有列的索引


添加新列时,idx_time_状态不再是覆盖索引,因为您正在选择*并且新列不在索引中,MySQL必须返回原始数据。这就是为什么MySQL认为不使用索引更有效。

覆盖索引只是故事的一部分

这是倒退的:

  KEY `idx_time_status` (`create_time`,`status`) USING BTREE
以=tests开始索引,然后以范围结束。也就是说,此索引更适合您的查询:

  INDEX(status, create_time)
这不必跨过状态为的行!=1.索引将它们过滤掉

但这并不能解释为什么要避开索引并切换到表扫描。解释这一点的是,范围可能超过表的20%。优化器查看统计数据并讨论在只需要几行时使用索引是否更快,或者在需要多行时忽略索引并简单地扫描表是否更快

如果您的测试用例在给定范围内有更多行,那么可能会有不同的解释


请参见我的

查看新表中显示20的行。看起来你在第一次解释之后插入了一些行。汉克斯·雅各布,你救了我一天。@Lunatictwo很高兴这有帮助。你能接受它作为答案吗?这是一个反对盲目使用SELECT*的论点。相反,请详细说明您真正需要的列。覆盖只是您看到内容的几个原因之一。是的,您是对的,原始索引应更改为状态,创建时间
  INDEX(status, create_time)