MYSQL 索引选择性陷阱

MYSQL 索引选择性陷阱

场景

用户表有1000个用户,其中有一个sex(性别)字段。sex字段上有一个sex索引。

但用户表有超过60%的用户sex为1(男性)

此时,执行语句

 explain select * from user where sex =1;
 +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--
|  1 | SIMPLE      | user  | NULL       | ALL  | sex           | NULL | NULL    | NULL |   14 |    71.43 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--



explain select * from user where sex = 0;
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-
|  1 | SIMPLE      | user  | NULL       | ref  | sex           | sex  | 4       | const |    4 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-

可以看到检索男性用户时,索引失效了。但检索女性时,索引依然可以用。

先看InnoDB的存储结构:

image-20210929132428902

以主键为索引时,速度很快,主键为聚集索引,因为每一条数据对应的主键都是有序的。

以其他列为索引时,索引按照字母表(abc…)的顺序排列的,每一条数据都有一个编号,对应着主键索引。

所以会出现LIKE头匹配命中索引(不一定),而尾匹配与任意匹配全表扫描的问题了。

为什么会出现头匹配仍然不命中索引?前面的性别索引又为什么失效?

索引选择性问题

不严谨的解释

命中的索引值超过总量的25%就可能产生索引选择性问题导致全表扫描(以EXPLAIN为准)

解决方法:

1.组合索引

 select * from user where name="姚" sex =1;

2.引入搜索引擎ES或Solr(更换数据源)

​ 将用户表导入到ES,ES基于分片多线程检索,解决查询慢的问题

3.强制使用索引(以实际运行效果为准)

select * from user force index(sex)  where sex =1;

4.增加缓存,提高全表检索速度(钞能力)

innodb_buffer_pool_size=16G
innodb_buffer_pool_instances=2
Licensed under CC BY-NC-SA 4.0
Last updated on Mar 23, 2024 06:11 UTC
让过去的过去,给时间点时间
Built with Hugo
Theme Stack designed by Jimmy