索引优化实践

SQL文件如下:
/*
Navicat MySQL Data Transfer

Source Server         : localhost
Source Server Version : 50022
Source Host           : localhost:3306
Source Database       : test

Target Server Type    : MYSQL
Target Server Version : 50022
File Encoding         : 65001

Date: 2020-03-13 16:57:10
*/

SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `employees`
-- ----------------------------
DROP TABLE IF EXISTS `employees`;
CREATE TABLE `employees` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(24) NOT NULL,
  `age` int(11) unsigned zerofill NOT NULL default '00000000000',
  `position` varchar(20) NOT NULL,
  `hire_time` timestamp NOT NULL default '0000-00-00 00:00:00' on update CURRENT_TIMESTAMP,
  PRIMARY KEY  (`id`),
  KEY `idx_name_age_position` (`name`,`age`,`position`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of employees
-- ----------------------------
INSERT INTO `employees` VALUES ('1', 'LiLei', '00000000022', 'mana ger', '0000-00-00 00:00:00');
INSERT INTO `employees` VALUES ('2', 'HanMeimei', '00000000023', 'dev', '2020-03-13 15:33:11');
INSERT INTO `employees` VALUES ('3', 'Lucy', '00000000023', 'dev', '0000-00-00 00:00:00');
 
1.全值匹配
mysql> EXPLAIN SELECT * FROM employees WHERE name= 'LiLei';
+----+-------------+-----------+------+-----------------------+-----------------------+---------+-------+------+-------------+
| id | select_type | table     | type | possible_keys         | key                   | key_len | ref   | rows | Extra       |
+----+-------------+-----------+------+-----------------------+-----------------------+---------+-------+------+-------------+
|  1 | SIMPLE      | employees | ref  | idx_name_age_position | idx_name_age_position | 74      | const |    1 | Using where |
+----+-------------+-----------+------+-----------------------+-----------------------+---------+-------+------+-------------+
1 row in set
 
mysql> EXPLAIN SELECT * FROM employees WHERE name= 'LiLei' AND age = 22;
+----+-------------+-----------+------+-----------------------+-----------------------+---------+-------------+------+-------------+
| id | select_type | table     | type | possible_keys         | key                   | key_len | ref         | rows | Extra       |
+----+-------------+-----------+------+-----------------------+-----------------------+---------+-------------+------+-------------+
|  1 | SIMPLE      | employees | ref  | idx_name_age_position | idx_name_age_position | 78      | const,const |    1 | Using where |
+----+-------------+-----------+------+-----------------------+-----------------------+---------+-------------+------+-------------+
1 row in set
 

mysql> EXPLAIN SELECT * FROM employees WHERE name= 'LiLei' AND age = 22 AND position ='manager';
+----+-------------+-----------+------+-----------------------+-----------------------+---------+-------------------+------+-------------+
| id | select_type | table     | type | possible_keys         | key                   | key_len | ref               | rows | Extra       |
+----+-------------+-----------+------+-----------------------+-----------------------+---------+-------------------+------+-------------+
|  1 | SIMPLE      | employees | ref  | idx_name_age_position | idx_name_age_position | 140     | const,const,const |    1 | Using where |
+----+-------------+-----------+------+-----------------------+-----------------------+---------+-------------------+------+-------------+
1 row in set

2.最左前缀法则
如果索引了多列,要遵守最左前缀法则。指的是查询从索引的最左前列开始并且不跳过索引
中的列。
 
3.不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转
向全表扫描
 
 
 
 
 
4.存储引擎不能使用索引中范围条件右边的列
 
5.尽量使用覆盖索引(只访问索引的查询(索引列包含查询列)),减少select *语句
 

mysql> EXPLAIN SELECT name,age FROM employees WHERE name= 'LiLei' AND age = 23 AND position ='manager';
+----+-------------+-----------+------+-----------------------+-----------------------+---------+-------------------+------+--------------------------+
| id | select_type | table     | type | possible_keys         | key                   | key_len | ref               | rows | Extra                    |
+----+-------------+-----------+------+-----------------------+-----------------------+---------+-------------------+------+--------------------------+
|  1 | SIMPLE      | employees | ref  | idx_name_age_position | idx_name_age_position | 140     | const,const,const |    1 | Using where; Using index |
+----+-------------+-----------+------+-----------------------+-----------------------+---------+-------------------+------+--------------------------+
1 row in set

mysql> EXPLAIN SELECT * FROM employees WHERE name= 'LiLei' AND age = 23 AND position ='manager';
+----+-------------+-----------+------+-----------------------+-----------------------+---------+-------------------+------+-------------+
| id | select_type | table     | type | possible_keys         | key                   | key_len | ref               | rows | Extra       |
+----+-------------+-----------+------+-----------------------+-----------------------+---------+-------------------+------+-------------+
|  1 | SIMPLE      | employees | ref  | idx_name_age_position | idx_name_age_position | 140     | const,const,const |    1 | Using where |
+----+-------------+-----------+------+-----------------------+-----------------------+---------+-------------------+------+-------------+
1 row in set

6.mysql在使用不等于(!=或者<>)的时候无法使用索引会导致全表扫描
 

7.is null,is not null 也无法使用索引

mysql> EXPLAIN SELECT * FROM employees WHERE name is null;
+----+-------------+-------+------+---------------+------+---------+------+------+------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra            |
+----+-------------+-------+------+---------------+------+---------+------+------+------------------+
|  1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL | Impossible WHERE |
+----+-------------+-------+------+---------------+------+---------+------+------+------------------+
1 row in set

mysql> EXPLAIN SELECT * FROM employees WHERE name is not 
null;
+----+-------------+-----------+------+-----------------------+------+---------+------+------+-------------+
| id | select_type | table     | type | possible_keys         | key  | key_len | ref  | rows | Extra       |
+----+-------------+-----------+------+-----------------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | employees | ALL  | idx_name_age_position | NULL | NULL    | NULL |    3 | Using where |
+----+-------------+-----------+------+-----------------------+------+---------+------+------+-------------+
1 row in set
mysql> 

8..like以通配符开头('$abc...')mysql索引失效会变成全表扫描操作

问题:解决like'%字符串%'索引不被使用的方法?
a)使用覆盖索引,查询字段必须是建立覆盖索引字段:

 b)如果不能使用覆盖索引则可能需要借助搜索引擎

9.字符串不加单引号索引失效
 

10.少用or或in,用它查询时,mysql不一定使用索引,mysql内部优化器会根据检索比例、
表大小等多个因素整体评估是否使用索引,详见范围查询优化
mysql> EXPLAIN SELECT * FROM employees WHERE name = 'LiLei' or name = 'HanMeimei';
+----+-------------+-----------+------+-----------------------+------+---------+------+------+-------------+
| id | select_type | table     | type | possible_keys         | key  | key_len | ref  | rows | Extra       |
+----+-------------+-----------+------+-----------------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | employees | ALL  | idx_name_age_position | NULL | NULL    | NULL |    3 | Using where |
+----+-------------+-----------+------+-----------------------+------+---------+------+------+-------------+
1 row in set
 
11. 范围查询优化
优化方法:可以讲大的范围拆分成多个小范围
 
给年龄添加单值索引:

mysql> ALTER TABLE `employees` ADD INDEX `idx_age` (`age`) ;
Query OK, 3 rows affected
Records: 3  Duplicates: 0  Warnings: 0

mysql> explain select * from employees where age >=1 and age <=2000;
+----+-------------+-----------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table     | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+----+-------------+-----------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | employees | range | idx_age       | idx_age | 4       | NULL |    1 | Using where |
+----+-------------+-----------+-------+---------------+---------+---------+------+------+-------------+
1 row in set

mysql> ALTER TABLE `employees` 
 DROP INDEX `idx_age`;
Query OK, 3 rows affected
Records: 3  Duplicates: 0  Warnings: 0

 
 
发布了640 篇原创文章 · 获赞 12 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/xiamaocheng/article/details/104842294