慢sql优化(二)

慢sql优化(二)

具体慢sql优化

隐式转换

隐式转换是指在查询条件中,将字符串类型的字段与数字类型的常量进行比较,MySQL会将字符串类型的字段转换为数字类型,然后再进行比较。这种转换会导致索引失效,从而导致全表扫描,影响查询性能。

最左匹配

MySQl建立联合索引时,会遵循最左前缀匹配的原则,即最左优先。如果你建立一个(a,b,c)的联合索引,相当于建立了(a)、(a,b)、(a,b,c)三个索引。

深分页问题

例如:select id,name,balance from account where create_time> ‘2020-09-19’ limit 100000,10;

1、通过普通二级索引树idx_create_time,过滤create_time条件,找到满足条件的主键id。

2、通过主键id,回到id主键索引树,找到满足记录的行,然后取出需要展示的列(回表过程)

3、扫描满足条件的100010行,然后扔掉前100000行,返回。
方法:减少回表次数来优化

  1. 标签记录法:就是标记一下上次查询到哪一条了;局限性:需要一种类似连续自增的字段。
    select id,name,balance FROM account where id > 100000 limit 10;
  2. 延迟关联法:就是把条件转移到主键索引树,然后减少回表
    优化思路就是,先通过idx_create_time二级索引树查询到满足条件的主键ID,再与原表通过主键ID内连接,这样后面直接走了主键索引了,同时也减少了回表。
    select acct1.id,acct1.name,acct1.balance FROM account acct1 INNER JOIN (SELECT a.id FROM account a WHERE a.create_time > ‘2020-09-19’ limit 100000, 10) AS acct2 on acct1.id= acct2.id;

in元素过多

分批进行

order by 走文件排序导致的慢查询

Using index condition;Using filesort
order by排序,分为全字段排序和rowid排序。它是拿max_length_for_sort_data和结果行数据长度对比,如果结果行数据长度超过max_length_for_sort_data这个值,就会走rowid排序,相反,则走全字段排序。

rowid排序 初始化sort_buffer,放入需要排序的age字段,以及主键id
全字段排序 初始化sort_buffer,放入需要查询的name、age、city字段

调整max_length_for_sort_data、sort_buffer_size等参数优化;

索引字段上使用is null, is not null,索引可能失效

单个name字段加上索引,并查询name为非空的语句,其实会走索引
单个card字段加上索引,并查询name为非空的语句,其实会走索引
但是它两用or连接起来,索引就失效了

索引字段上使用(!= 或者 < >),索引可能失效

左右连接,关联的字段编码格式不一样

user表的name字段编码是utf8mb4,而user_job表的name字段编码为utf8

group by使用临时表

group by使用不当,很容易就会产生慢SQL问题。因为它既用到临时表,又默认用到排序。有时候还可能用到磁盘临时表。

如果执行过程中,会发现内存临时表大小到达了上限(控制这个上限的参数就是tmp_table_size),会把内存临时表转成磁盘临时表。

如果数据量很大,很可能这个查询需要的磁盘临时表,就会占用大量的磁盘空间。

优化方法:
group by 后面的字段加索引

order by null 不用排序:执行计划中,不再出现“Using filesort”

尽量只使用内存临时表

使用SQL_BIG_RESULT:消除临时表

SQL_SMALL_RESULT:显示指定用内存表(memory引擎)

SQL_BIG_RESULT:显示指定用磁盘临时表(myisam引擎或innodb引擎)

两者区别在于,使用磁盘临时表可以借助主键做去重排序,适合大数据量;使用内存表写入更快,然后在内存中排序,适合小数据量

delete + in子查询不走索引

避免在where子句中使用or来连接条件

使用union all来代替or
分开两条sql

1.使用or可能会使索引失效,从而全表扫描:

尽量使用数值替代字符串类型

1.主键(id):primary key优先使用数值类型int,tinyint
2.性别(sex):0代表女,1代表男;数据库没有布尔类型,mysql推荐使用tinyint

1.因为引擎在处理查询和连接时会逐个比较字符串中每一个字符:
2.而对于数字型而言只需要比较一次就够了;
3.字符会降低查询和连接的性能,并会增加存诸开销;

批量插入性能提升

默认新增$QL有事务控制,导致每条都需要事务开启和事务提交,而批量处理是一次事务开启和提交,效率提升明显

避免在索引列上使用内置函数

使用索引列上内置函数,索引失效。

mysql优化之表碎片

表碎片的产生的原因是经常进行删除插入更改等操作,每当删除了一行内容,这段空间就会变空白,日复一日的大量操作就会让这种空白占用更大的空间。
当执行插入操作时,Mysql会尝试使用空白空间,但如果某个空白空间一致没被合适的数据占用,该空白就会一直留着。
表碎片会存在于表空间内,每当mysql要从磁盘读取数据时,就会需要跨越额外的空白碎片才能取到需要的数据,即会造成额外的IO支出。
所以,定期清理表碎片是很有必要的。不过主要注意的是:清理表碎片的过程会锁表,尽量选在业务低峰期进行。mysql官方建议每周或者每月整理一次即可。

使用 【OPTIMIZE TABLE 你的表】,以下简称‘OPT’

使用OPT出现阻塞其它sql执行,业务高峰期执行会导致查询失败,或者接口返回失败
OPT会深度清理表空间以及表的碎片,将之前删除数据占用的空间和索引重新整理
OPT命令在表数据千万级别时严重耗时,建议档表数据量小的时候整理
2、使用 【ALTER TABLE 你的表 ENGINE=INNODB;】
此命令不会阻塞其它sql
此命令不会深度清理碎片,但是可以基本达到OPT命令一样的效果
以六千万级别的数据为例,耗时大概在4小时左右
可以重复执行,重复执行会重新清理表碎片

参考文献:

https://blog.csdn.net/qq877192055/article/details/131321092
https://blog.csdn.net/guorui_java/article/details/126542005

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值