空表情况下,优化器不用预定索引一次现象

Posted 一头猪的奇妙旅行

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了空表情况下,优化器不用预定索引一次现象相关的知识,希望对你有一定的参考价值。

错误描述:表行如下,表中数据为空,进行执行分析时候,发现优化器没有按照预定那样走第二条索引,很奇怪

mysql> show create table answer_survey_info\G
*************************** 1. row ***************************
Table: answer_survey_info
Create Table: CREATE TABLE `answer_survey_info` (
`answerId` bigint(64) NOT NULL AUTO_INCREMENT,
`surveyId` bigint(64) NOT NULL,
`questionId` bigint(64) NOT NULL,
`uin` varchar(255) DEFAULT NULL,
`userNumber` varchar(128) DEFAULT NULL,
`selectId` bigint(64) DEFAULT NULL,
`answerText` varchar(5000) DEFAULT NULL,
`emailAddress` varchar(64) DEFAULT NULL,
`ip` varchar(64) DEFAULT NULL,
`createTime` datetime DEFAULT NULL,
PRIMARY KEY (`answerId`),
KEY `surveyId_questionId_selectId_index` (`surveyId`,`questionId`,`selectId`),
KEY `surveyId_uin_index` (`uin`,`surveyId`)
) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

mysql> 
mysql> 
mysql> 
mysql> 
mysql> show full columns from answer_survey_info;
+--------------+---------------+-----------------+------+-----+---------+----------------+---------------------------------+---------+
| Field | Type | Collation | Null | Key | Default | Extra | Privileges | Comment |
+--------------+---------------+-----------------+------+-----+---------+----------------+---------------------------------+---------+
| answerId | bigint(64) | NULL | NO | PRI | NULL | auto_increment | select,insert,update,references | |
| surveyId | bigint(64) | NULL | NO | MUL | NULL | | select,insert,update,references | |
| questionId | bigint(64) | NULL | NO | | NULL | | select,insert,update,references | |
| uin | varchar(255) | utf8_general_ci | YES | MUL | NULL | | select,insert,update,references | |
| userNumber | varchar(128) | utf8_general_ci | YES | | NULL | | select,insert,update,references | |
| selectId | bigint(64) | NULL | YES | | NULL | | select,insert,update,references | |
| answerText | varchar(5000) | utf8_general_ci | YES | | NULL | | select,insert,update,references | |
| emailAddress | varchar(64) | utf8_general_ci | YES | | NULL | | select,insert,update,references | |
| ip | varchar(64) | utf8_general_ci | YES | | NULL | | select,insert,update,references | |
| createTime | datetime | NULL | YES | | NULL | | select,insert,update,references | |
+--------------+---------------+-----------------+------+-----+---------+----------------+---------------------------------+---------+
10 rows in set (0.00 sec)

mysql> 
mysql> 
mysql> 
mysql>

  

检查是否又是索引字符集的问题,由于是复合索引,使用他的左前缀的行作为索引行,发现都能够正常运行

mysql> explain select * from answer_survey_info where uin=‘15953‘;
+----+-------------+--------------------+------+--------------------+--------------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------------+------+--------------------+--------------------+---------+-------+------+-------------+
| 1 | SIMPLE | answer_survey_info | ref | surveyId_uin_index | surveyId_uin_index | 768 | const | 1 | Using where |
+----+-------------+--------------------+------+--------------------+--------------------+---------+-------+------+-------------+
1 row in set (0.00 sec)

mysql> 
mysql> 
mysql> explain select * from answer_survey_info where surveyId=10006; 
+----+-------------+--------------------+------+------------------------------------+------------------------------------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------------+------+------------------------------------+------------------------------------+---------+-------+------+-------+
| 1 | SIMPLE | answer_survey_info | ref | surveyId_questionId_selectId_index | surveyId_questionId_selectId_index | 8 | const | 1 | |
+----+-------------+--------------------+------+------------------------------------+------------------------------------+---------+-------+------+-------+
1 row in set (0.00 sec)

mysql> 
mysql>

  

将第二索引的两行作为where判断,希望能走第二条索引(有个前提条件,第二条复合索引的右边行刚好是第一条索引的左前缀),结果如下,很是吃惊

mysql> explain select * from answer_survey_info where uin=‘15953‘ and surveyId=10006;
+----+-------------+--------------------+------+-------------------------------------------------------+------------------------------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------------+------+-------------------------------------------------------+------------------------------------+---------+-------+------+-------------+
| 1 | SIMPLE | answer_survey_info | ref | surveyId_questionId_selectId_index,surveyId_uin_index | surveyId_questionId_selectId_index | 8 | const | 1 | Using where |
+----+-------------+--------------------+------+-------------------------------------------------------+------------------------------------+---------+-------+------+-------------+
1 row in set (0.00 sec)

  


由于数据的分布会影响优化器做出执行计划,所以考虑往里面放上一些数据,下面的存储过程往里面插入了10w条数据

mysql> delimiter $$


mysql> create procedure test() 
-> begin 
-> declare num int; 
-> set num=1; 
-> while num <= 100000 do 
-> insert into answer_survey_info values (null,FLOOR(RAND() * 10000),FLOOR(RAND() * 10000),FLOOR(RAND() * 10000),FLOOR(RAND() * 10000),FLOOR(RAND() * 10000),FLOOR(RAND() * 10000),FLOOR(RAND() * 10000),FLOOR(RAND() * 10000),now()); set num=num+1;
-> end while;
-> end;
-> $$
Query OK, 0 rows affected (0.00 sec)

mysql> call test();
-> $$
Query OK, 1 row affected (10.28 sec)

  


再次进行查询,现在已经正常了

mysql> explain select * from answer_survey_info where uin=‘2‘ and surveyId=1680;
+----+-------------+--------------------+------+-------------------------------------------------------+--------------------+---------+-------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------------+------+-------------------------------------------------------+--------------------+---------+-------------+------+-------------+
| 1 | SIMPLE | answer_survey_info | ref | surveyId_questionId_selectId_index,surveyId_uin_index | surveyId_uin_index | 776 | const,const | 1 | Using where |
+----+-------------+--------------------+------+-------------------------------------------------------+--------------------+---------+-------------+------+-------------+
1 row in set (0.00 sec)

mysql> 
mysql> 
mysql>

  

以上是关于空表情况下,优化器不用预定索引一次现象的主要内容,如果未能解决你的问题,请参考以下文章

mybatis 查询时间时候为啥用不到时间字段上的索引

mysql测试

数据量太大的情况下,如何优化查询速度?

Oracle SQL调优

Mysql索引--05---索引失效的11种情况

Oracle优化器