当前位置:网站首页>SQL调优小记
SQL调优小记
2022-07-06 09:32:00 【Stray_Lambs】
目录
SQL优化
当存在慢SQL时,我们首先需要检测一下SQL语句是否可以进行优化(写SQL的时候就需要思考能否优化),然后,再考虑性能优化。
SQL语句优化
负向查询不能使用索引
当我们使用not in的时候,哪怕中了索引, 也是相当于失效的。
select name from user where id not in (1,3,4);
-- 应该修改为
select name from user where id in (2,5,6);
前导模糊查询不能使用索引
在使用like匹配字符时,若%在前面,则索引失效。
select name from user where name like '%zhangsan'
-- 尽可能改为
select name from user where name like 'zhangsan%'
建议可以考虑使用 Lucene
等全文索引工具来代替频繁的模糊查询。
数据区分不明显时,不应该建立索引
如果数据字段无法明显区分,则不应该建立索引,因为建立索引会消耗空间,就像一本50页的书有50页的目录。
字段的默认值不要为null
null可能会在数据查询时,进行类型的隐式转化,导致索引失效,而且可能会导致查询的结果与预期不一致。
在字段上进行计算不能命中索引
计算函数尽量不要在字段上进行,即不要转换字段类型或者对字段操作(计算、函数、类型转换(手动or自动)),会导致索引失效,转向全表扫描。
select name from user where FROM_UNIXTIME(create_time) < CURDATE();
-- 应该修改为
select name from user where create_time < FROM_UNIXTIME(CURDATE());
最左前缀问题
--如果给 user 表中的 username pwd 字段创建了复合索引那么使用以下SQL 都是可以命中索引:
select username from user where username='zhangsan' and pwd ='axsedf1sd'
select username from user where pwd ='axsedf1sd' and username='zhangsan'
select username from user where username='zhangsan'
-- 但是使用如下,索引无法命中
select username from user where pwd ='axsedf1sd'
明确返回条数
如果明确返回条数,则查询时约束数量,减少查询量,如
select name from user where username='zhangsan' limit 1
不要让数据库自动强制类型转换
如果左右两边类型不一致时,会进行强制类型转换,然后进行全盘扫描。
select name from user where telno=18722222222
--应该修改为
select name from user where telno='18722222222'
join时两表字段类型要相同
不然索引失效,无法命中。
小结
索引失效的产生情况:
1、全值匹配我最爱;
2、最佳左前缀法则;
3、不在索引列上做任何操作(计算、函数、类型转换(手动or自动)),会导致索引失效,转向全表扫描;
4、存储引擎不能使用索引中范围条件右边的列;
5、尽量使用覆盖索引(只访问索引列(查询列和索引列一致)),减少select *;
6、MySQL在使用不等于运算符(!=或<>)时,无法使用索引,会导致全表扫描;
7、is null和is not null,无法使用索引;
8、like若以通配符开头(’%aa’),则索引失效,全表扫描;***–解决方法:1、通配符放左边 2、使用覆盖索引(见P40)***
9、字符串不加引号导致索引失效(相当于使用了隐式的类型转换–见第3条);
10、少用or,用它来连接条件时,索引失效。
口诀
全值匹配我最爱,最左前缀要遵守;
带头大哥不能死,中间兄弟不能断;
索引列上少计算,范围之后全失效;
LIKE百分写最右,覆盖索引不写*;
不等空值还有or,索引失效要少用。
SQL性能优化
使用Explain进行SQL分析
Explain 用来分析 SELECT 查询语句,开发人员可以通过分析 Explain 结果来优化查询语句。
比较重要的字段有:
- select_type : 查询类型,有简单查询、联合查询、子查询等
- key : 使用的索引
- rows : 扫描的行数
优化数据访问量
减少请求的访问量
- 只返回必要的列: 最好不要使用 SELECT * 语句。
- 只返回必要的行: 使用 LIMIT 语句来限制返回的数据。
- 缓存重复查询的数据: 使用缓存可以避免在数据库中进行查询,特别在要查询的数据经常被重复查询时,缓存带来的查询性能提升将会是非常明显的。
减少服务器端扫描行数
最有效的方式是使用索引来覆盖查询。
重构查询方法
切分大查询
一个大查询如果一次性执行的话,可能一次锁住很多数据、占满整个事务日志、耗尽系统资源、阻塞很多小的但重要的查询。每次限定条数,可以有效减少阻塞。
DELEFT FROM messages WHERE create < DATE_SUB(NOW(), INTERVAL 3 MONTH);
-- 应修改为
rows_affected = 0
do {
rows_affected = do_query(
"DELETE FROM messages WHERE create < DATE_SUB(NOW(), INTERVAL 3 MONTH) LIMIT 10000")
} while rows_affected > 0
分解大连接查询
将一个大连接查询分解成对每一个表进行一次单表查询,然后将结果在应用程序中进行关联,这样做的好处有:
- 让缓存更高效。对于连接查询,如果其中一个表发生变化,那么整个查询缓存就无法使用。而分解后的多个查询,即使其中一个表发生变化,对其它表的查询缓存依然可以使用。
- 分解成多个单表查询,这些单表查询的缓存结果更可能被其它查询使用到,从而减少冗余记录的查询。
- 减少锁竞争;
- 在应用层进行连接,可以更容易对数据库进行拆分,从而更容易做到高性能和可伸缩。
- 查询本身效率也可能会有所提升。例如下面的例子中,使用 IN() 代替连接查询,可以让 MySQL 按照 ID 顺序进行查询,这可能比随机的连接要更高效。
SELECT * FROM tab
JOIN tag_post ON tag_post.tag_id=tag.id
JOIN post ON tag_post.post_id=post.id
WHERE tag.tag='mysql';
修改为(有点分布式的思想)
SELECT * FROM tag WHERE tag='mysql';
SELECT * FROM tag_post WHERE tag_id=1234;
SELECT * FROM post WHERE post.id IN (123,456,567,9098,8904);
边栏推荐
- @RequestMapping、@GetMapping
- Activiti目录(四)查询代办/已办、审核
- MySQL日期函数
- ~78 radial gradient
- Yao BanZhi and his team came together, and the competition experts gathered together. What fairy programming competition is this?
- Mongodb在node中的使用
- Instructions for Redux
- TCP's three handshakes and four waves
- Shell_ 04_ Shell script
- MySQL string function
猜你喜欢
一个数10年工作经验的微服务架构老师的简历
Mongodb learning notes
Instructions for Redux
ByteDance 2022 school recruitment R & D advance approval publicity meeting, students' top 10 issues
Install docker under windows10 (through Oracle VM VirtualBox)
TCP's three handshakes and four waves
这群程序员中的「广告狂人」,把抖音广告做成了AR游戏
100张图训练1小时,照片风格随意变,文末有Demo试玩|SIGGRAPH 2021
程序员定位解决问题方法论
Set up the flutter environment pit collection
随机推荐
Shell_ 02_ Text three swordsman
Full record of ByteDance technology newcomer training: a guide to the new growth of school recruitment
吴军三部曲见识(五) 拒绝伪工作者
Fdog series (III): use Tencent cloud SMS interface to send SMS, write database, deploy to server, web finale.
算数运算指令
Ruoyi-Cloud 踩坑的BUG
Control transfer instruction
~86m rabbit practice
Activiti目录(三)部署流程、发起流程
redux使用说明
Activiti directory (I) highlights
Activit零零碎碎要人命的坑
字节跳动技术面试官现身说法:我最想pick什么样的候选人
yum install xxx报错
冯诺依曼体系结构
8086 CPU internal structure
Go language uses the thrift protocol to realize the client and service end reports not enough arguments in call to oprot Writemessagebegin error resolution
谢邀,人在工区,刚交代码,在下字节跳动实习生
字节跳动2022校招研发提前批宣讲会,同学们最关心的10个问题
逻辑运算指令