工作中遇到的99%SQL优化,这里都能给你解决方案
前几篇文章介绍了mysql的底层数据结构和mysql优化的神器explain。后台有些朋友说小强只介绍概念,平时使用还是一脸懵,强烈要求小强来一篇实战sql优化,经过周末两天的整理和总结,sql优化实战新鲜出炉, 大家平时学习和工作中,遇到的90% 的sql优化都会介绍到,介意篇幅过长,分成3篇文章哈。
- CREATE TABLE `employees` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `name` varchar(24) NOT NULL DEFAULT '' COMMENT '姓名',
- `age` int(20) NOT NULL DEFAULT '0' COMMENT '年龄',
- `position` varchar(20) NOT NULL DEFAULT '' COMMENT '职位',
- `hire_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '入职时间',
- PRIMARY KEY (`id`),
- KEY `idx_name_age_position` (`name`,`age`,`position`) USING BTREE
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='员工表';
- insert into employees(name,age,position,hire_time) values('LiLei', 22, 'manager', NOW())
- insert into employees(name,age,position,hire_time) values('HanMeimei', 23, 'dev', NOW())
- insert into employees(name,age,position,hire_time) values('Lucy', 23, 'dev', NOW())
全值匹配
索引的字段类型是varchar(n):2字节存储字符串长度,如果是utf-8, 则长度是3n+2
- EXPLAIN select * from employees where name='LiLei';
![工作中遇到的99%SQL优化,这里都能给你解决方案](https://s5.51cto.com/oss/201912/02/420885ced56f068b835b9297e6b96f42.jpeg)
- EXPLAIN select * from employees where name='LiLei' AND age = 22;
![工作中遇到的99%SQL优化,这里都能给你解决方案](https://s4.51cto.com/oss/201912/02/8e3b73d97bcb4bbadb73f8e9473be1eb.jpeg)
- EXPLAIN select * from employees where name='LiLei' AND age = 22 AND position = 'manager';
![工作中遇到的99%SQL优化,这里都能给你解决方案](https://s1.51cto.com/oss/201912/02/082e0e79cf7d11d8c976a8093b3c547e.jpeg)
最左前缀法则
如果索引是多列,要最受最左前缀法则。指的是查询从索引的最左前列开始并且不跳过索引中的列。以下三条sql根据最左前缀法则,都不会走索引。
- EXPLAIN select * from employees where age = 22 AND position='manager';
- EXPLAIN select * from employees where position ='manager';
- EXPLAIN select * from employees where age=17;
![工作中遇到的99%SQL优化,这里都能给你解决方案](https://s1.51cto.com/oss/201912/02/8f0c4537f5e2b4445ef90d34c48809f3.jpeg)
索引失效
不要在索引列上做任何操作(计算、函数、类型转换),会导致索引失效而转向全表扫描。
- EXPLAIN select * from employees where name='LiLei';
![工作中遇到的99%SQL优化,这里都能给你解决方案](https://s4.51cto.com/oss/201912/02/d1fd2810b8f875dd8fa791d79e93e4d5.jpeg)
- EXPLAIN select * from employees where left(name, 3)='LiLei';
![工作中遇到的99%SQL优化,这里都能给你解决方案](https://s4.51cto.com/oss/201912/02/70bb7c391a3deaac9a91d3d4682ccee4.jpeg)
给hire_time增加一个普通索引:
- alter table `employees` ADD INDEX `idx_hire_time`(`hire_time`) USING BTREE;
- EXPLAIN select * from employees where date(hire_time) = '2019-08-25';
![工作中遇到的99%SQL优化,这里都能给你解决方案](https://s4.51cto.com/oss/201912/02/eef7a0c49164c24d014d6af25d9bdf51.jpeg)
还原最初索引状态
- ALTER TABLE `employees` DROP INDEX `idx_hire_time`;
存储引擎不能使用索引中范围条件右边的列
- -- EXPLAIN SELECT * FROM employees WHERE name ='LiLei' AND age=22 AND position ='manager';
- EXPLAIN SELECT * FROM employees WHERE name ='LiLei' AND age>22 AND position ='manager';
![工作中遇到的99%SQL优化,这里都能给你解决方案](https://s3.51cto.com/oss/201912/02/68fe37a5cf12da2951c074b83194ffa9.jpeg)
看到key_len这个索引长度是78, 也就是只使用到了前两个字段name和age,postition没有使用到索引的。
覆盖索引
尽量使用覆盖索引(只访问索引的查询(索引列包含查询列)),减少selelct * 语句。
- EXPLAIN SELECT name,age,position FROM employees WHERE name ='LiLei' AND age=22 AND position ='manager';
![工作中遇到的99%SQL优化,这里都能给你解决方案](https://s1.51cto.com/oss/201912/02/19de228aea2ee91a3d95796124d86f73.jpeg)
条件判断
mysql在使用不等于(! = 或者 <>)的时候无法使用索引会导致全表扫描
- EXPLAIN SELECT * FROM employees WHERE name !='LiLei' ;
![工作中遇到的99%SQL优化,这里都能给你解决方案](https://s5.51cto.com/oss/201912/02/fcb2ca4c79a2bcda7de5cbe4cccb6a7d.jpeg)
空值判断
is null,is not null也无法使用索引
- EXPLAIN SELECT * FROM employees WHERE name is null;
![工作中遇到的99%SQL优化,这里都能给你解决方案](https://s4.51cto.com/oss/201912/02/be6c13784dada25b12389a40ef54e7d7.jpeg)
like
like以通配符开头(‘$abc’)mysql索引失效会变成全表扫描操作
- EXPLAIN SELECT * FROM employees WHERE name LIKE '%Lei';
![工作中遇到的99%SQL优化,这里都能给你解决方案](https://s5.51cto.com/oss/201912/02/f4380c0844c8d517cc722a715988cd8a.jpeg)
字符串不加单引号索引失效
- EXPLAIN SELECT * FROM employees WHERE name ='1000';
- EXPLAIN SELECT * FROM employees WHERE name =1000;
![工作中遇到的99%SQL优化,这里都能给你解决方案](https://s2.51cto.com/oss/201912/02/b9e92c2defc7ce6c6797ced20ce34900.jpeg)
不加单引号的字符串,mysql底层会使用cust函数将其转换为字符串,此时索引失效。
or&in少使用
少用or或in,用它查询时,mysql不一定使用索引,mysql内部优化器会根据索引比例、表大小等多个因素整体评估是否使用索引。
- EXPLAIN SELECT * FROM employees WHERE name ='LiLei' or name='HanMeimei';
![工作中遇到的99%SQL优化,这里都能给你解决方案](https://s3.51cto.com/oss/201912/02/23e944ea70dd93f015a9ff2f651a5f86.jpeg)
范围查询优化
给年龄添加单值索引
- ALTER TABLE `employees`ADD INDEX `idx_age`(`age`) USING BTREE;
- EXPLAIN select * from employees where age > 1 and age <= 2000;
![工作中遇到的99%SQL优化,这里都能给你解决方案](https://s5.51cto.com/oss/201912/02/2d0c92c024dd7f6918f18b19655b2689.jpeg)
没有走索引原因:mysql内部优化器会根据检索比例、表大小等多个因素整体评估是否使用索引。这个例子没有走索引可能是因为单次数据量查询过大导致优化器最终选择不走索引。优化方法:可以将大的范围拆分成多个小范围。
相关文章
- 教你使用TensorFlow2对阿拉伯语手写字符数据集进行识别
- 如何使用TensorFlow和自编码器模型生成手写数字
- 2015年数据库漏洞威胁报告(下载)
- 给Dubbo贡献源码,做梦都在修bug
- "挖掘机指数"告诉你不一样的中国经济
- 大数据预测雾霾以及存在的商机
- 什么数据库比较适合数据分析师
- 2017年中美数据科学对比报告,Python排名第一,年薪中位数高达11万美金
- 大数据信用评级:保持手机高电量会让你更容易贷到款?
- 教你使用TensorFlow2判断细胞图像是否感染
- Redis 作者谈如何处理维护开源项目面对的精神压力
- 盘点:数据新闻的七种生产模式
- 数据可视化入门——我该从何开始?
- 警惕大数据中的“陷阱”
- 谷歌、Facebook频繁发现CPU内核不可靠,出现无法预测计算错误
- 民生银行高级数据分析师张丹:用R语言把数据玩出花样
- PHPer、Laravel面试可能遇到的问题及答案
- Redis 实战篇:巧用数据类型实现亿级数据统计
- Flink实时计算Pv、Uv的几种方法
- 手把手教你用ECharts画散点图和气泡图