数据库索引失效如何避免

十大原则:

1.全值匹配我最爱
2.最佳左前缀法则
3.不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描
4.存储引擎不能使用索引中范围条件右边的列
5.尽量使用覆盖索引(只访问索引的查询(索引列和查询列一致), 减少select *
6. mysql在使用不等于(!=或者<>)的时候无法使用索引会导致全表扫描
7.is null,is not null也无法使用索引
8. like以通配符开头(%abc... )mysq|索引失效会变成全表扫描的操作er问题:解决like "%6字符串%时索引不被使用的方法?
9.字符串不加单引号索引失效
10.少用or,用它来连接时会索引失效

 

当使用like进行模糊查询的时候,'%'写在首尾两端好,还是左边好,还是右边好

mysql> explain select * from user where name like '%aa%';
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | user  | ALL  | NULL          | NULL | NULL    | NULL |    5 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)

mysql> explain select * from user where name like '%aa';
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | user  | ALL  | NULL          | NULL | NULL    | NULL |    5 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)

mysql> explain select * from user where name like 'aa%';
+----+-------------+-------+-------+------------------+------------------+---------+------+------+-------------+
| id | select_type | table | type  | possible_keys    | key              | key_len | ref  | rows | Extra       |
+----+-------------+-------+-------+------------------+------------------+---------+------+------+-------------+
|  1 | SIMPLE      | user  | range | idx_user_nameAge | idx_user_nameAge | 767     | NULL |    1 | Using where |
+----+-------------+-------+-------+------------------+------------------+---------+------+------+-------------+
1 row in set (0.00 sec)

通过以上测试,结果表明:当我们在实际开发中如果要用到like实现模糊查询,前提是这三者查询出来的结果都相同时,选'%'放在右边的比较好,这里一定要记住有前提。

 

如何解决模糊查询like后面的条件字符串首尾都用到'%'而导致的索引失效问题?——解决方案:使用索引覆盖

示例:

1、先创建一张user表

1 CREATE TABLE `user` (
2   `id` int(11) NOT NULL AUTO_INCREMENT,
3   `name` varchar(255) NOT NULL,
4   `age` int(11) NOT NULL,
5   `sex` char(1) DEFAULT 'F',
6   PRIMARY KEY (`id`),
7   KEY `idx_user_nameAge` (`name`,`age`)
8 ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 

2、然后向表中添加记录

insert into user (name, age) values ('0aa0', 20);
insert into user (name, age) values ('1aa1', 21);
insert into user (name, age) values ('2aa2', 22);
insert into user (name, age) values ('3aa3', 19);
insert into user (name, age) values ('4aa4', 23);

 3、没有索引覆盖

添加索引之前

mysql> show index from user;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| user  |          0 | PRIMARY  |            1 | id          | A         |           5 |     NULL | NULL   |      | BTREE      |         |               |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)

mysql> explain  select * from user where name like '%aa%';
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | user  | ALL  | NULL          | NULL | NULL    | NULL |    5 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)

添加组合索引(idx_user_nameAge)之后

mysql> create index idx_user_nameAge on user(name, age);
Query OK, 0 rows affected (0.64 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show index from user;
+-------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name         | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| user  |          0 | PRIMARY          |            1 | id          | A         |           5 |     NULL | NULL   |      | BTREE      |         |               |
| user  |          1 | idx_user_nameAge |            1 | name        | A         |           5 |     NULL | NULL   |      | BTREE      |         |               |
| user  |          1 | idx_user_nameAge |            2 | age         | A         |           5 |     NULL | NULL   |      | BTREE      |         |               |
+-------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.00 sec)

mysql> explain  select * from user where name like '%aa%';
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | user  | ALL  | NULL          | NULL | NULL    | NULL |    5 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)

通过以上代码,可以观察出,加了索引之后,如果查询的是 * (即所有字段)时,type类型的值仍然是ALL,显然性能没有得到提升,因为此时select后面所要查询的字段没有完全被索引字段所覆盖(专业名词简称索引覆盖),所以对于like的模糊查询后面条件字符串的首位都加'%'的情况,要想提高查询效率,将type类型的值从ALL提高到index,必须要利用索引覆盖

4、索引覆盖

--------------------------------------------------------------------------------------------------------------------------
select 后面查询的字段都被索引覆盖

mysql> explain select id from user where name like '%aa%'; +----+-------------+-------+-------+---------------+------------------+---------+------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+------------------+---------+------+------+--------------------------+ | 1 | SIMPLE | user | index | NULL | idx_user_nameAge | 771 | NULL | 5 | Using where; Using index | +----+-------------+-------+-------+---------------+------------------+---------+------+------+--------------------------+ 1 row in set (0.00 sec) mysql> explain select name, age from user where name like '%aa%'; +----+-------------+-------+-------+---------------+------------------+---------+------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+------------------+---------+------+------+--------------------------+ | 1 | SIMPLE | user | index | NULL | idx_user_nameAge | 771 | NULL | 5 | Using where; Using index | +----+-------------+-------+-------+---------------+------------------+---------+------+------+--------------------------+ 1 row in set (0.00 sec) mysql> explain select id, name, age from user where name like '%aa%'; +----+-------------+-------+-------+---------------+------------------+---------+------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+------------------+---------+------+------+--------------------------+ | 1 | SIMPLE | user | index | NULL | idx_user_nameAge | 771 | NULL | 5 | Using where; Using index | +----+-------------+-------+-------+---------------+------------------+---------+------+------+--------------------------+ 1 row in set (0.00 sec)
--------------------------------------------------------------------------------------------------------------------------
select 后面查询的字段没有全被索引覆盖
mysql
> explain select sex from user where name like '%aa%'; +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | 1 | SIMPLE | user | ALL | NULL | NULL | NULL | NULL | 5 | Using where | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ 1 row in set (0.00 sec) mysql> explain select * from user where name like '%aa%'; +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | 1 | SIMPLE | user | ALL | NULL | NULL | NULL | NULL | 5 | Using where | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ 1 row in set (0.00 sec)

此时,从后面两句SQL的执行情况来看,就不难发现:索引覆盖对于like模糊查询条件字符串首尾都加'%'时查询效率有了大大的提升,不再是之前的ALL(全表扫描)了。

posted @ 2021-06-29 17:08  没有你哪有我  阅读(225)  评论(0编辑  收藏  举报