常用MySQL优化

在这里插入图片描述

1、SQL语句中IN包含的值不应过多

MySQL对于IN做了相应的优化,即将IN中的常量全部存储在一个数组里面,而且这个数组是排好序的。但是如果数值较多,产生的消耗也是比较大的。
比如

SELECT id FROM t_test WHERE id IN(1,2,3);

对于这种连续的数值,能用BETWEEN就不要用IN,再或者使用连接来替换。

2、SELECT语句务必指明字段名称

SELECT * 增加很多不必要的消耗(CPU、IO、内存、网络带宽)增加了使用覆盖索引的可能性,当表结构发生改变时,字段也需要更新。所以要求直接在SELECT后面接上字段名。

3、当只需要一条数据的时候,使用 LIMIT 1

这是为了使用EXPLAINtype列达到const类型

4、如果排序字段没有用到索引,尽量少排序

5、如果限制条件中其他字段没有索引,尽量少用 OR

OR两边的字段中,如果有一个不是索引字段,而其他条件也不是索引字段,会造成该查询不走索引的情况。很多时候使用 UNION ALL或者是UNION(必要的时候)的方式来代替OR会得到更好的效果。

6、尽量用 UNION ALL 代替 UNION

UNIONUNION ALL的差异主要是前者需要将结果集合并后再进行唯一性过滤操作,这就会涉及到排序,增加大量的CPU运算,加大资源消耗及延迟。当然,UNION ALL的前提条件是两个结果集没有重复数据。

7、不使用 ORDER BY RAND()

SELECT id FROM t_test ORDER BY RAND() LIMIT 1000;
优化为
SELECT id FROM t_test t1 JOIN (SELECT RAND()* (SELECT MAX(id) t_test) AS nid) t2 ON t1.id > t2.nid LIMIT 1000;

8、区分 INEXISTSNOT INNOT EXISTS

SELECT * FROM 表A WHERE id IN(SELECT id FROM 表B)

上面SQL语名相当于

SELECT * FROM 表A WHERE EXISTS(SELECT * FROM 表B WHERE 表B.id = 表A.id)

区分 INEXISTS 主要是造成了驱动顺序的改变(这是性能变化的关键),如果是 EXISTS,那么以外层表为驱动表,先被访问,如果是 IN ,那么先执行子查询。所以 IN 适合于外表大而内表小的情况,EXISTS 适合于外表小而内表大的情况。

关于 NOT INNOT EXISTS,推荐使用 NOT EXISTS,不仅仅是效率问题,NOT IN 可能存在逻辑问题。

高效写出一个替代 NOT EXISTS 的SQL语句。

原SQL语句

SELECT colname.... FROM 表A WHERE a.id NOT IN(SELECT b.id FROM 表B)

优化SQL语句

SELECT colname.... FROM 表A LEFT JOIN 表B ON WHERE a.id = b.id WHERE b.id IS NULL

表A不在表B中的数据

9、使用合理的分布方式以提高分布的效率

SELECT id,name,age FROM preson LIMIT 866331, 20

使用上述SQL语句做分页的时候,可能有人会发现,随着表数据量的增加,直接使用LIMIT分页查询会越来越慢。

优化的方法如下:可以取前一页的最大行数的id,然后根据这个最大的id来限制下一页的起点。比如此列中,上一页最大的id是866331。SQL可以采用如下的写法:

SELECT id,name,age FROM preson WHERE id > 866331 LIMIT 20

10、避免在 WHERE 子句中对字段进行 NULL 值判断

对于 NULL 的判断会导致引擎放弃使用索引而进行全表扫描。

11、不建议使用 % 前缀模糊查询

例如 LIKE "%name" 或者 LIKE "%name%",这种查询会导致索引失效而进行全表扫描。但是可以使用 LIKE "name%"

如何查询 %name%

创建全文索引SQL语法

ALTER TABLE `t_test` ADD FULLTEXT INDEX `idx_user_name`(`user_name`);

使用全文索引SQL语句

SELECT id,name,age FROM t_test WHERE MATCH(user_name) AGAINST("张三" IN BOOLEAN mode);

注意:在需要创建全文索引之前,请联系DBA确定能否创建,同 时需要注意的是查询语句的写法与普通索引的区别。

12、避免在 WHERE 子句中对字段进行表达式操作

SELECT id,name FROM t_test WHERE age * 22 = 36;

对字段运行了算术运算,会造成引擎放弃使用索引,建议改成

SELECT id,name FROM t_test WHERE age = 36 / 2;

13、避免隐匿类型转换

WHERE 子句中出现 COLUMN 字段的类型和传入的参数类型不一致的时候发生的类型转换,建议先确定WHERE 中的参数类型。

14、对于联合索引来说,要遵守最左前缀法则。

举列来说索引含有字段id、name、school,可以直接用id字段,也可以id、name这样的顺序,但是name;school都无法使用这个索引。所以在创建联合索引的时候一定要注意索引字段顺序,常用的查询字段放在最前面。

15、必要时可以使用 FORCE INDEX 来强制查询出某个索引

有的时候MySQL优化器采取它认为合适的索引来检索SQL语句,但是可能它所采用的索引并不是我们想要的。这时就可以采用FORCE INDEX来强制优化器使用我们制定的索引。

16、注意范围查询语句

对于联合索引来说,如果存在范围查询,比如 BETWEEN>< 等条件时,会造成后面的索引字段失效。

17、关于 JOIN优化

LEFT JOIN 以左边的表为驱动表,INNER JOIN 自动找出那个数据少的表作为驱动表,RIGHT JOIN 以右表为驱动表。

1、MySQL中淌有 FULL JOIN,可以用以下方式来解决

SELECT * FROM A LEFT JOIN B on B.name = A.name WHERE B.name is NULL UNION ALL SELECT * FROM B;

2、尽量使用 INNER JOIN,避免 LEFT JOIN
参与联合查询的表至少为2张表,一般都存在大小之分。如果连接方式是INNER JOIN,在没有其他过滤条件的情况下MySQL会自动选择小表作为驱动表,但是LEFT JOIN在驱动表的选择上遵循的是左边驱动右边驱动的原则,即LEFT JOIN左边的表名为驱动表。
3、合理利用索引
被驱动表的索引字段作为 ON 的限制字段。
4、利用小表去驱动多大表
这样可以减少嵌套循环中的循环次数,以减少IO总量及CPU运算的次数。

5、巧用STRAIGHT_JOIN
INNER JOIN是由MySQL选择驱动表,但是有些特殊情况需要选择另个表作为驱动表,比如有GROUP BYORDER BY「Using filesort」「Using temporary」时。STRAIGHT_JOIN来强制连接顺序,在STRAIGHT_JOIN左边的表名就是驱动表,右边则是被驱动表。在使用STRAIGHT_JOIN有个前提条件是该查询是内连接,也就是INNER JOIN。其他链接不推荐使用STRAIGHT_JOIN,否则可能造成查询结果不准确。

最后感谢阅读,写得不对的地方请指教。

原文地址:https://caozongpeng.github.io/2019/01/29/常用MySQL优化/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值