问:有哪些常见的SQL优化手段?
这也是个高频面试题,并且并非面试造火箭的那种问题,实际项目中也会有非常多的地方需要进行SQL优化
避免使用 Select *
select *
中,无用字段会增加网络带宽消耗,特别是varchar
、blob
、text
等大字段select *
无法使用Mysql优化器覆盖索引的优化。
覆盖索引
:即一个查询可以完全通过索引来满足,不需要回表回表
:根据非聚集索引查询到主键,然后根据主键查询其他数据。
分页优化
Mysql分页时,并不是跳过 offset,而是取 offset + N 行,然后丢弃 offset行,只返回N行。
并且,offset 越大、N 越大、select出的字段越多,耗时就越久。
数据量少时,分页耗时还是比较少的。
但是上数据量上百万甚至千万的时候,直接limit 1000000, 20
是非常慢的。
优化方案:先根据排序规则及limit条件查询出主键,然后根据主键关联到表本身。
即把
select t.* form the_table where 条件 limit 1000000, 20
修改为:
select t1.* from the_table t1,
(select id from the_table where 条件 limit 1000000, 20) as t2
where t1.id = t2.id
并且条件种的字段尽量创建了索引。
尽量避免多表Join
join 关联的效率不算很高,多个表关联时会使用嵌套循环,如果关联字段没有索引,会直接使用笛卡尔积实现 join,导致全表扫描,效率很低。
两种解决方式:
- 单表查询,根据查询结果进行二次查询,最后在 Service 层进行关联。
- 数据冗余:把重要字段冗余在表中,尽可能避免关联查询。
推荐使用第一种方式,因为数据库的计算资源更加宝贵,Service层可以很方便的水平扩展。并且如果数据量非常大的时候也会进行分库分表,这也会限制join。
建议不要使用外键与级联
外键概念应该在应用层解决。
选择合适的字段类型
存储字节越小,占用空间就越小,性能也就越好。
尽量使用 union all
代替 union
union
会把结果集进行去重操作,更耗时。
批量操作
操作数据时,能批量操作尽量批量处理,减少请求数据库的次数。
使用Explain
分析SQL
正确使用索引
适合作为索引的字段
- 不为null的字段:索引字段应尽量不为null,对于数据为null的字段,数据库比较难优化。如果字段频繁被查询,又无法避免为null,可以使用-1、0、true、false等语义清晰地短字符作为代替。
- 被频繁查询的字段
- 被作为条件查询的字段
- 频繁需要排序的字段
- 频繁用于外连接的字段
被频繁更新的字段应慎重建立索引
虽然索引能带来查询上的效率,但是维护索引的成本也不小。
如果字段不经常被查询,反而经常被修改,那不应该在这种字段上创建索引。
尽可能创建联合索引,而不是单列索引
索引需要占用空间,如果是联合索引,多个字段在一个索引上,可以节省空间,并且修改数据时效率也会提升。
避免冗余索引
考虑在字符串类型上使用前缀索引代替普通索引
前缀索引只适用于字符串类型,比普通索引占用更少的空间
避免索引失效
- 使用
select *
查询 - 创建了联合索引,但是没有遵循最左匹配原则
- 在索引列上进行计算、函数、类型转换等操作
- 以
%
开头的like查询,比如like '%abc'
- 发生隐式转换
- 查询时使用
条件1 or 条件2
,如果条件1或者条件2中存在未创建索引的字段,就不会使用索引