sql优化的相关建议

1. in和exists:
区别主要是驱动顺序的不一样(驱动顺序也是性能变化的关键),exists是以外层表为驱动表,先被访问,而in,则是先执行子查询。这样很多人就立马明白了,in适合于外表大而内表小,而EXISTS适合于外表小而内表大的情况。所以如果有两个表A、B,若表A数据量大则优先选择in,即:
select * from A 
where id in (select id from B);
若表B数据量大则优先选择exists,即:
select * from A
where exists  (select * from B where A. id=B.id);
备注1:not in 和 not exists的使用雷同,但推荐使用not exists,不仅仅是效率问题,not in可能存在逻辑问题。最好还是都不用,用左连接效率最高,示例如下:
select* from a
Left join b on a.id=b.id 
where b.id is null;
而且MySQL对IN做了相应的优化,将IN中的常量全部存储在一个数组里面,而且这个数组是排好序的。但是如果数值较多,产生的消耗也比较大。所以 对于连续的数值,能用between就不要用in了;再或者使用连接来替换。
备注2:说到between,当两边查询的是时间日期格式时需要注意,举例如下:
select * from A where time between '2017-01-01' and '2017-01-03'
发现虽然:日期时间between and 包含了1月3日,但是查询结果没有1月3日,这个问题是由于time是日期时间格式,这样between '2017-01-01' and '2017-01-03'等价于'between 2017-01-01 00:00:00 and 2017-01-03 00:00:00',但2017-01-03 00:00:00等于2017-01-02 23:59:59,所以时间筛选中只包含1日和2日的数据,所以我们可以将日前时间类型转换成日期,即条件改成date(time) between '2017-01-01' and '2017-01-03' 就可以了。

2. 避免select *:
SELECT *会增加很多不必要的消耗(cpu、io、内存、网络带宽);增加了使用覆盖索引的可能性;当表结构发生改变时,前端也需要更新。所以SELECT语句务必指明字段名称。后面我举例用*是为了省事,不要学坏哈。

3. or的使用:
如果限制条件中其他字段没有索引,尽量少用or,因为or两边的字段中,如果有一个不是索引字段,而其他条件也不是索引字段,会造成该查询不走索引的情况。很多时候使用 union all 或者是union(必要的时候)的方式来代替“or”会得到更好的效果

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

5. order by的使用:
如果排序字段没有用到索引,就尽量少排序。

6. null的使用场景:
不必要的时候避免在where子句中对字段进行null值判断,因为对于null的判断会导致引擎放弃使用索引而进行全表扫描。

7. like的使用:
在使用like的时候不建议使用%前缀模糊查询,例如LIKE “%name”或者LIKE “%name%”,这种查询也会导致索引失效而进行全表扫描。但是可以使用LIKE “name%”。如果一定要使用%name%的话,就需要创建全文索引,创建语句如下:
ALTER TABLE `table_name` ADD FULLTEXT INDEX `idx_user_name`(`user_name`);
创建完之后我们就可以使用了:
select * from table_name 
where match(user_name) against('zhangsan' in boolean mode);

8. 公式/表达式:
避免在where子句中对字段进行表达式操作,如:
select * from table_name where age*2=36;
建议改成:
select * from table_name where age=36/2;

9. 索引的使用:
对于联合索引来说,要遵守最左前缀法则。举列来说索引含有字段id,name,school,可以直接用id字段,也可以id,name这样的顺序,但是name,school都无法使用这个索引。所以在创建联合索引的时候一定要注意索引字段顺序,常用的查询字段放在最前面。但对于联合索引来说,如果存在范围查询,比如between,>,<等条件时,会造成后面的索引字段失效。
备注:MySQL优化器采取它认为合适的索引来检索sql语句,但是可能它所采用的索引并不是我们想要的。这时就可以采用force index来强制优化器使用我们制定的索引。

10. join:
假如A join B:
LEFT JOIN:A表为驱动表;
INNER JOIN:MySQL会自动找出那个数据少的表作用驱动表;但是有些特殊情况需要选择另个表作为驱动表,比如有group by、order by等「Using filesort」、「Using temporary」时。但可以用STRAIGHT_JOIN来强制连接顺序,在STRAIGHT_JOIN左边的表就是驱动表,在使用STRAIGHT_JOIN有个前提条件是该查询是内连接,也就是inner join。其他链接不推荐使用,可能会造成查询结果不准确。
RIGHT JOIN:B表为驱动表。
MySQL中没有full join,可以用以下方式来解决:
select * from A left join B on B.id = A.id
where B.id is null
union all
select * from B;
在join的时候应该:尽量使用inner join,避免left join;合理利用索引;被驱动表的索引字段作为on的限制字段;利用小表去驱动大表
参与联合查询的表至少为2张表,一般都存在大小之分。如果连接方式是inner join,在没有其他过滤条件的情况下MySQL会自动选择小表作为驱动表,但是left join在驱动表的选择上遵循的是左边驱动右边的原则,即left join左边的表名为驱动表。

我这也是在其他网友那学习总结的,并不是原创,后续如果再有更多的优化学习心得我会随时补充哈

  • 9
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Trisyp

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值