浅谈 SQL 优化
- SQL 优化目标:避免全表查询,降低磁盘IO,提高查询效率。
执行顺序
在有优化 SQL 之前,我们需要先了解一下 SQL 执行过程,每个语句的执行顺序。
# 选择字段、去重
SELECT DISTINCT COLUMN, ...
# 聚合函数
AGG_FUNC(COLUMN OR expression), ...
# 选择表
FORM [left_table]
# 链接
<join_type> JOIN <right_table>
# 链接条件
ON <join_condition>
# 条件过滤
WHERE <where_condition>
# 分组
GROUP BY <group_by_list>
# 分组过滤
HAVING <having_condition>
# 排序
ORDER BY <order_by_list>
# 分页
LIMIT COUNT OFFSET COUNT;
执行顺序 | 关键词 | 功能 |
---|---|---|
1 | FORM [left_table] | 选择表 |
2 | ON <join_condition> | 链接条件 |
3 | <join_type> JOIN <right_table> | 链接 |
4 | WHERE <where_condition> | 条件过滤 |
5 | GROUP BY <group_by_list> | 分组 |
6 | AGG_FUNC(COLUMN OR expression), ... | 聚合函数 |
7 | HAVING <having_condition> | 分组过滤 |
8 | SELECT DISTINCT COLUMN, ... | 选择字段、去重 |
9 | ORDER BY <order_by_list> | 排序 |
10 | LIMIT COUNT OFFSET COUNT | 分页 |
基础优化
- 尽可能指定查询字段,而不是使用 select *
- 避免在 where 子句中使用 or 来连接条件,推荐使用 union all 替换
- 使用 varchar 代替 char
- 尽量使用数值替代字符串类型
尽可能指定查询字段,而不是使用 select *
原因:
- 节省资源,减少网络开销。
- select * 查询时,很可能不会用到索引,造成全表查询。
避免在 where 子句中使用 or 来连接条件,推荐使用 union all 替换
原因:
- 使用 or 可能使索引失效,造成全表查询。
使用 varchar 代替 char
- varchar变长字段按照数据内容实际长度存储,存储空间小,可以节省存储空间。
- char按声明大小存储,不足补空格
尽量使用数值替代字符串类型
扩展
如何优化 SQL 慢查询?
- 分析语句,是否加载了不必要的字段/数据。
- 分析 SQL 执行计划(explain extended),思考可能的优化点,是否命中索引等。
- 查看 SQL 涉及的表结构和索引信息。
- 如果 SQL 很复杂,优化 SQL 结构。
- 按照可能的优化点执行表结构变更、增加索引、SQL 改写等操作。
- 查看优化后的执行时间和执行计划。
- 如果表数据量太大,考虑分表。
- 利用缓存,减少查询次数。
怎么创建索引
不了解什么是索引的,可以先看这篇文章【浅析数据库索引】
- 索引不宜太多,一般5个以内。
推荐创建索引情况
- 频繁出现在
where
查询条件的字段 - 多表查询中与其它表进行
on
关联的字段,外键关系 - 查询中经常用来排序的字段
- 查询中经常用来统计或者分组字段
不建议创建索引情况
- 频繁更新的字段:每次更新都需要更新索引
- where条件查询中用不到的字段
- 经常增删改的表:每次更新都需要更新索引
- 重复记录非常多的情况
单列索引/复合索引怎么选择?
高并发下倾向创建复合索引。
什么情况索引不生效?
- 有or必全有索引;
- 复合索引未用左列字段;
- like以%开头;
- 需要类型转换;
- where中索引列有运算;
- where中索引列使用了函数;
- 如果mysql觉得全表扫描更快时(数据少);
使用 explain 分析 SQL 执行计划
TODO: 后续举例详细说说。
评论