MySQL SQL常用优化主要有where,range,order,group by,or等查询。下图是优化的原则,后面会有一个例子来看看:
- 对于where和range来说,按照优先最左匹配原则,其次跨列的索引条件下推,这会导致部分索引字段失效,最后是全部扫描,通过MySQL服务器来过滤存储引擎返回的数据。
- 对于order排序来说,优先使用索引扫描来排序,其次是文件排序,文件排序可能在内存也能在磁盘。
- 对于group分组来说,优先使用索引来分组,但是分为稀疏索引分组和紧密索引分组,通常情况下,稀疏索引效果更好,因为可以跳过索引顺序来扫描,也可以理解为跨桶扫描,其次是紧密索引分组,最后用临时表分组。
- 对于or来说,给每一个字段加独立索引,然后优化器会进行索引合并。
案例
建表如下:
CREATE TABLE
t1
(c1
int DEFAULT NULL,c2
int DEFAULT NULL,c3
int NOT NULL,c4
int DEFAULT NULL, KEYidx
(c1
,c2
,c3
) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3
比如我们为t1建立了联合索引(c1,c2,c3),c4美元加索引。c1,c2,c3的索引长度分别为5,5,4。因为c3字段是int,占4个字节,而c1是int,但是可以为NULL,所以额外使用一个字节存储NULL的索引字段。数据有50条:
点查
SELECT * FROM training.t1 where c3 =1 and c2=1 and c1=1 ;
使用了索引,只要全部包含索引列,那么点查顺序无所谓,索引长度为14:
SELECT * FROM training.t1 where c2=1 and c1=1 ;
使用了索引,只要包含了首列c1,c1和c2顺序无所谓,索引长度为10:
SELECT * FROM training.t1 where c3=1 and c1=1 ;
使用了索引,但是索引条件下推了,只要包含了首列,跨列顺序无所谓,会使用索引下推,但是c3无法走索引,索引长度是5,只用了c1字段索引:
SELECT * FROM training.t1 where c2=1 and c3=1;
不包含首列c1,那么会索引失效,走全部扫描:
范围查询
SELECT * FROM t1 where c3>1 and c1>1 and c2>1;
只有c1用到了索引,c2,c3没用到索引,索引长度是5,可以看出范围查询很简单,只要一列用了范围查询,后面的列都不会走索引,但是会走索引下推:
SELECT * FROM t1 where c3>1 and c2>1;
没有c1,会直接全部扫描:
SELECT * FROM t1 where c1=1 and c2>1 and c3=1;
用到了索引字段c1,c2。字段c3无法使用索引,索引长度是10,c3列走了索引下推优化:
排序
排序优先索引排序,这就要求查询和排序字段都必须要order by子句中:
SELECT c1,c2,c3 FROM t1 order by c1; SELECT c1,c2,c3 FROM t1 order by c1,c2; SELECT c1,c2,c3 FROM t1 order by c1,c2,c3; SELECT c1,c2,c3 FROM t1 where c1=1 order by c2,c3; SELECT c1,c2,c3 FROM t1 where c1>1 order by c1,c2,c3;
以上都利用了索引排序。
SELECT c1,c2,c3,c4 FROM t1 order by c1,c2,c3;
由于查询列不包括索引字段,所以使用了文件排序:
SELECT c1,c2,c3 FROM t1 order by c1 asc,c2 desc
排序的方向不一样,使用了文件排序:
SELECT c1,c2,c3 FROM t1 where c1=2 order by c1 asc,c2 desc
排序方向不一样,出现了backward index scan(反向索引扫描)
SELECT c1,c2,c3 FROM t1 order by c1 asc,c4 asc
排序不在索引的列,会导致filesort:
SELECT c1,c2,c3 FROM t1 where c1>2 order by c2,c3
索引列第一个是范围查询,排序使用后面索引会导致filesort:
参考
where优化:https://dev.mysql.com/doc/refman/8.0/en/where-optimization.html range优化:https://dev.mysql.com/doc/refman/8.0/en/range-optimization.html 排序优化:https://dev.mysql.com/doc/refman/8.0/en/order-by-optimization.html 分组优化:https://dev.mysql.com/doc/refman/8.0/en/group-by-optimization.html