MySQL索引失效 VERSION = 5.7.37
组合索引 idx_enterprise_id_owner_id_warehouse_id(enterprise_id, owner_id, warehouse_id)
EXPLAIN SELECT * FROM store_customer_order_20230922 WHERE warehouse_id = 33495628344758272
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: store_customer_order_20230922
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 373630
filtered: 10.00
Extra: Using where
1 row in set, 1 warning (0.01 sec)
以下SQL满足最左匹配,
索引生效
EXPLAIN SELECT * FROM store_customer_order_20230922 WHERE enterprise_id = 33494065698107392 AND warehouse_id = 33495628344758272
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: store_customer_order_20230922
partitions: NULL
type: ref
possible_keys: idx_enterprise_id_owner_id_warehouse_id
key: idx_enterprise_id_owner_id_warehouse_id
key_len: 8
ref: const
rows: 15244
filtered: 10.00
Extra: Using index condition
1 row in set, 1 warning (0.01 sec)
回表范围超过一定比例值会导致索引失效 组合索引 idx_enterprise_id_owner_id_warehouse_id(enterprise_id, owner_id, warehouse_id)
EXPLAIN SELECT * FROM store_customer_order_20230922 WHERE warehouse_id = 33495628344758272
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: store_customer_order_20230922
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 373630
filtered: 10.00
Extra: Using where
1 row in set, 1 warning (0.01 sec)
以下SQL索引覆盖,
索引生效
EXPLAIN SELECT warehouse_id,enterprise_id FROM store_customer_order_20230922 WHERE warehouse_id = 33495628344758272
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: store_customer_order_20230922
partitions: NULL
type: index
possible_keys: idx_enterprise_id_owner_id_warehouse_id
key: idx_enterprise_id_owner_id_warehouse_id
key_len: 24
ref: NULL
rows: 373630
filtered: 10.00
Extra: Using where; Using index
1 row in set, 1 warning (0.00 sec)
EXPLAIN SELECT * FROM store_customer_order_20230922 WHERE customer_order_id + 1=33944879566856193
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: store_customer_order_20230922
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 381663
filtered: 100.00
Extra: Using where
1 row in set, 1 warning (0.01 sec)
EXPLAIN SELECT * FROM store_customer_order_20230922 WHERE SUBSTR(customer_order_id,1,17)=33944879566856193
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: store_customer_order_20230922
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 381663
filtered: 100.00
Extra: Using where
1 row in set, 1 warning (0.00 sec)
varchar <- int 字段类型是varchar, 查询条件是int,
索引失效
CREATE TABLE t_1 (
...
trace_id varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '链路ID'
KEY idx_trace_id (trace_id)
...
) ENGINE=InnoDB
表记录条数 = 2138670
mysql> EXPLAIN SELECT * FROM t_1 WHERE trace_id = '527455599584432128';
+----+-------------+----------------------------+------------+------+---------------+--------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+----------------------------+------------+------+---------------+--------------+---------+-------+------+----------+-------+
| 1 | SIMPLE | t_1 | NULL | ref | idx_trace_id | idx_trace_id | 258 | const | 2 | 100.00 | NULL |
+----+-------------+----------------------------+------------+------+---------------+--------------+---------+-------+------+----------+-------+
mysql> EXPLAIN SELECT * FROM t_1 WHERE trace_id = 527455599584432128;
+----+-------------+----------------------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+----------------------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| 1 | SIMPLE | t_1 | NULL | ALL | idx_trace_id | NULL | NULL | NULL | 1773276 | 10.00 | Using where |
+----+-------------+----------------------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
int <- varchar 字段类型是int, 查询条件是varchar, MySQL会将varchar类型隐式转换成int,
索引生效 以下2条SQL都可以查询 customer_order_id = 33931868273811456 数据.
SELECT * FROM store_customer_order WHERE customer_order_id = '33931868273811456a';
SELECT * FROM store_customer_order WHERE customer_order_id = '33931868273811456';
CREATE TABLE `school` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`school_code` varchar(255) DEFAULT NULL,
`school_name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_school_code` (`school_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
CREATE TABLE `student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`school_code` varchar(255) DEFAULT NULL,
`student_name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_school_code` (`school_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
以下SQL导致索引失效
SELECT j.*,t.* FROM school t, student j WHERE t.school_code = j.school_code AND j.school_code = 'S001'
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 5
filtered: 100.00
Extra: Using where
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: j
partitions: NULL
type: ref
possible_keys: idx_school_code
key: idx_school_code
key_len: 1023
ref: const
rows: 197
filtered: 100.00
Extra: NULL
修改 school 表的字符编码为 utf8mb4, 索引生效.
SELECT j.*,t.* FROM school t, student j WHERE t.school_code = j.school_code AND j.school_code = 'S001'
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t
partitions: NULL
type: ref
possible_keys: idx_school_code
key: idx_school_code
key_len: 1023
ref: const
rows: 1
filtered: 100.00
Extra: NULL
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: j
partitions: NULL
type: ref
possible_keys: idx_school_code
key: idx_school_code
key_len: 1023
ref: const
rows: 197
filtered: 100.00
Extra: Using index condition
CREATE TABLE `t2` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`t_status` int(11) NOT NULL,
`year` int(11) NOT NULL,
`create_time` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_status` (`t_status`),
KEY `idx_year` (`year`)
) ENGINE=InnoDB
8.1 以下SQL
索引失效
SELECT * FROM t_order WHERE t_status=1 OR year=2023 OR create_time='2023-09-24 12:19:00'
使用关键字OR,那么在它的前面和后面的字段都要有索引, 否则索引失效 8.2
回表范围超过一定比例值会导致索引失效 验证如下
表中数据9999条,t_status=1数据3374条,year=2023数据2531条
以下SQL
索引生效
SELECT * FROM t2 WHERE t_status=1 OR year=2023
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t2
partitions: NULL
type: index_merge
possible_keys: idx_status,idx_year
key: idx_status,idx_year
key_len: 4,4
ref: NULL
rows: 5905
filtered: 100.00
Extra: Using union(idx_status,idx_year); Using where
表中数据19998条,t_status=1数据13373条,year=2023数据12530条
以下相同SQL
索引失效
SELECT * FROM t2 WHERE t_status=1 OR year=2023
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t2
partitions: NULL
type: ALL
possible_keys: idx_status,idx_year
key: NULL
key_len: NULL
ref: NULL
rows: 19840
filtered: 27.55
Extra: Using where
1.回表范围超过一定比例值会导致索引失效 2.range_optimizer_max_mem_size 设置过小
IN子查询回表范围超过一定比例值会导致索引失效
CREATE TABLE `t2` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`t_status` int(11) NOT NULL,
`year` int(11) NOT NULL,
`create_time` datetime(3) DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
KEY `idx_status` (`t_status`),
KEY `idx_year` (`year`),
KEY `idx_create_time` (`create_time`)
) ENGINE=InnoDB
表中数据19999条,t_status=1数据3条,,t_status=2数据10条,t_status=3数据19986条
以下SQL
索引生效
SELECT * FROM t2 WHERE t_status NOT IN (2,3)
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t2
partitions: NULL
type: range
possible_keys: idx_status
key: idx_status
key_len: 4
ref: NULL
rows: 5
filtered: 100.00
Extra: Using index condition
以下SQL
索引失效
SELECT * FROM t2 WHERE t_status NOT IN (1,2)
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t2
partitions: NULL
type: ALL
possible_keys: idx_status
key: NULL
key_len: NULL
ref: NULL
rows: 19838
filtered: 50.01
Extra: Using where
回表范围超过一定比例值会导致索引失效 验证如下
CREATE TABLE `t2` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`order_id` int(11) NOT NULL,
`order_status` int(11) NOT NULL,
`phone` varchar(11) DEFAULT NULL,
`create_time` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_phone` (`phone`)
) ENGINE=InnoDB
说明: 表中总条数15136, 其中 phone IS NULL 条数14022
以下SQL,索引失效
SELECT * FROM t2 WHERE phone IS NULL
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t2
partitions: NULL
type: ALL
possible_keys: idx_phone
key: NULL
key_len: NULL
ref: NULL
rows: 14959
filtered: 93.74
Extra: Using where
以下SQL,索引生效
SELECT phone FROM t2 WHERE phone IS NULL
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t2
partitions: NULL
type: ref
possible_keys: idx_phone
key: idx_phone
key_len: 14
ref: const
rows: 14022
filtered: 100.00
Extra: Using where; Using index
回表范围超过一定比例值会导致索引失效 验证如下
CREATE TABLE `t2` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`order_id` int(11) NOT NULL,
`order_status` int(11) NOT NULL,
`phone` varchar(11) DEFAULT NULL,
`create_time` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_phone` (`phone`)
) ENGINE=InnoDB
说明: 表中总条数39999, 其中 phone IS NOT NULL 条数31113
以下SQL,索引失效
SELECT * FROM t2 WHERE phone IS NOT NULL
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t2
partitions: NULL
type: ALL
possible_keys: idx_phone
key: NULL
key_len: NULL
ref: NULL
rows: 40296
filtered: 50.00
Extra: Using where
以下SQL,索引生效
SELECT phone FROM t2 WHERE phone IS NOT NULL
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t2
partitions: NULL
type: range
possible_keys: idx_phone
key: idx_phone
key_len: 14
ref: NULL
rows: 20148
filtered: 100.00
Extra: Using where; Using index
回表范围超过一定比例值会导致索引失效 验证如下
CREATE TABLE `t2` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`t_status` int(11) NOT NULL,
`year` int(11) NOT NULL,
`create_time` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_status` (`t_status`),
KEY `idx_year` (`year`)
) ENGINE=InnoDB
表中数据9999条,t_status=1数据11条,t_status=3数据9988条
以下SQL,
索引失效
SELECT * FROM t2 WHERE t_status != 1
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t2
partitions: NULL
type: ALL
possible_keys: idx_status
key: NULL
key_len: NULL
ref: NULL
rows: 10107
filtered: 98.83
Extra: Using where
以下SQL,
索引生效
SELECT * FROM t2 WHERE t_status != 3
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t2
partitions: NULL
type: range
possible_keys: idx_status
key: idx_status
key_len: 4
ref: NULL
rows: 12
filtered: 100.00
Extra: Using index condition
当查询条件涉及ORDER BY, LIMIT等条件时, 索引是否生效情况比较复杂,而且与MySQL版本有关.
通常普通索引,未使用LIMIT, 则索引失效
ORDER BY多个索引字段时, 可能索引失效
建议在使用时进行EXPLAIN验证