Files
Hui-s-notebook/慢SQL优化.md
lostecho 0e31c0d985 add file
2024-05-13 20:50:11 +08:00

160 lines
6.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 优化方式
数据量
- SQL 执行后返回给客户端的数据量的大小
- 数据量越大需要扫描的 I/O 次数越多,数据库服务器的 IO 瓶颈
取数据的方式
- 数据在缓存还是磁盘
- 能否通过全局索引快速寻址
- 是否结合谓词条件命中全局索引加速扫描
数据加工的方式
- 排序、子查询、聚合、关联等需要将数据取到临时表中,再对数据加工
- 对于数据量多的计算,会消耗大量 CPU 资源
- 是否选择了合适的 join 方式
## 优化思路
减少数据扫描(磁盘访问)
- 尽量在查询中加入一些可以提前过滤数据的位于条件,减少数据扫描量,对查询更加友好
- 扫描大表数据时是否可以命中索引,减少回表,避免全表扫描
返回更少数据(减少网络传输或磁盘访问)
减少交互次数(减少网络传输)
- 将数据存放在更快的地方
- 某条查询涉及大表,无法进一步优化,如果返回数据量不大但访问频率很高,可以将返回的数据放在应用端缓存或 redis 缓存中,提高存取速度
减少服务器开销CPU 和内存)
避免大事务
利用更多资源
## 优化案例
- 数据分页优化
```sql
select * from table_name where type = ? limit ?,?;
```
偏移 id
```sql
lastId = 0 or min(id)
do {
select * from table_name where type = ? and id > {#lastId} limit ?;
lastId = max(id)
} while (isNotEmpty)
```
分段查询
优点:可并行查询,分段互不依赖
缺点:依赖连续性,数据过于分散代价较高
```sql
minId = min(id) maxId = max(id)
for(int i = minId; i <= maxId; i+=pageSize){
select * from table_name where type = ? and id between i and i+ pageSize;
}
```
- 优化 groupBy
将不需要的数据在 groupBy 之前过滤掉
```sql
select job, avg(sal) from table_name group by job having job = 'manager'
```
```sql
select job, avg(sal) from table_name where job = 'manager' group by job
```
- 范围查询
联合索引中如果某个列存在范围查询(大于小于),其右边的列是否还有意义
设计时需要结合业务需求
- 优化 order by
索引
```sql
KEY `idx_account_trade_date_time` (`account_number`,`trade_date_time`)
KEY `idx_trade_date_time` (`trade_date_time`)
KEY `idx_create_time` (`create_time`)
```
慢 SQL
```sql
select id,,,creator,modifier,create_time,update_time from satatement where (account_number = 'XXX' and create_time > '2024-04-24 00:00:00' and create_time < '2024-04-25 00:00:00' and dc_flag = 'C') order by trade_date_time desc, id desc limit 0,1000;
```
```sql
select id,,,creator,modifier,create_time,update_time from satatement where (account_number = 'XXX' and create_time > '2024-04-24 00:00:00' and create_time < '2024-04-25 00:00:00' and dc_flag = 'C') order by create_time desc, id desc limit 0,1000;
```
MySQL 使不使用索引与所查列无关只与索引本身where 条件order by group by 字段有关,索引的作用为查找和排序
- 业务拆分
```sql
select * from order where status = 'S' and update_time < now-5min limit 500
```
业务数据增长status 无法走索引,结合业务特性,对数据获取按日期拆分
```sql
date = now; minDate = now - 10 day
while(date > minDate) {
select * from order where order_date = #{date} and status = 'S' and update_time < now-5min limit 500
date = date + 1
}
```
## 数据库结构优化
- 范式优化表的设计合理化3 NF消除冗余节省空间
- 反范式优化:适当添加冗余(减少 join
- 拆分表:分区将数据在物理上分隔开,不同分区数据表存储于不同磁盘中,查询时只需到表分区中扫描,无需全表扫描,同时分散了磁盘 IO
## SQL 语句优化
1. 避免子查询
2. 用 in 替换 or
3. 读取适当的记录 limit MN不要读取多余的记录
4. 禁止不必要的 order by 排序
5. 总和查询禁止排重用 union all
6. 避免随机取数据
7. 将多次插入换成批量插入
8. 只返回必要的列select 具体字段
9. 区分 in 和 exist
10. 优化 group by
11. 尽量使用数字型字段
12. 优化 join 语句
## 大表优化
- 分库分表
- 读写分离
- 数据定期归档
## 索引的优缺点
优点
- 提高查询语句执行效率,减少 IO 操作次数
- 创建唯一性索引,保证数据库中每一行数据的唯一性
- 加索引的列会进行排序,使用分组和排序子句可以减少时间
缺点
- 索引需要占用一定空间
- 创建索引和维护索引需要时间
- 对表中数据进行修改时,索引也要动态维护,降低了更新效率
## 索引结构
## 数据行格式
MySQL 有 4 种存储格式:
1. Compact
2. Redundant5.0 版本前,已废弃)
3. DynamicMySQL 5.7 默认格式)
4. Compressed
Dynamic 下,对于处理行溢出,仅存放溢出页内存地址
## 索引设计原则
哪些情况适合建索引
- 数据有唯一性限制
- 频繁 where 条件
- 进场 group by 和 order by 字段,都有时建议联合索引
- 经常 distinct 字段
- 多表连接时的字段
- 数量最好不要超过 3 张
- 多表查询时 where 条件建索引
- 对连接字段建索引,且数据类型保持一致
- 确定数据范围情况下使用数据类型较小的字段,索引也会占空间
- 字符串建索引使用前缀
- 节省空间
- 可定位到相同前缀,然后通过主键查询完整字符串
- 区分度高的字段(散列性高)的字段
- 多个字段需要建索引,联合索引优于单值索引
不需要索引
- where 条件中用不到
- 数据量小,小于 1000 条
- 大量重复数据的列
- 避免在经常更新的表或字段
- 不建议主键使用无序的值
- 不定义冗余或重复索引
- 已有联合索引不要单独再建单索引
## 索引优化之 MRR
## 索引下推
idx (name, age)
```sql
select * from tuser where name like '张%' and age=10;
```
直接在联合索引里面过滤过滤两次完后在回表
条件
- 只能用于 range、ref、eq_ref、ref_or_null 访问方法
- 只使用 InnoDB 和 MyISAM
- 对存储引擎来说,只适用于二级索引(辅助索引)
- 引用了子查询的条件不能下推
- 引用了存储函数的条件不能下推,存储引擎无法调用存储函数