当前位置: 首页 > 后端技术 > Java

SQL优化就是这样做的!

时间:2023-04-01 20:55:32 Java

作者:狼王\来源:https://www.cnblogs.com/power...1.前言应用开发初期,数据量较小,开发者更注重实现开发功能时的功能。随着生产数据的增长,很多SQL语句开始暴露性能问题,对生产的影响也越来越大。有时这些有问题的SQL可能是整个系统性能的瓶颈。二、SQL优化的一般步骤1、通过慢查询日志等定位执行效率低的SQL语句。2、说明分析SQL执行计划,需要重点关注type、rows、filtered、extra。从上到下打字,效率越来越高。ALL全表扫描;索引索引全扫描;范围索引范围扫描,常用词<、<=、>=、between、in等操作;ref使用非唯一索引扫描或唯一索引前缀扫描,返回单条记录,常出现在关系查询中;eq_ref与ref类似,不同的是它使用了唯一索引和主键相关查询;const/系统单条记录,系统会将匹配行中的其他列当作常量,比如主键或唯一索引查询;nullMySQL不访问任何表或索引,直接返回结果;虽然从上到下效率越来越高,但是根据成本模型,假设有两个索引idx1(a,b,c),idx2(a,c),SQL是“select*fromtwherea=1和bin(1,2)orderbyc";如果使用idx1,则类型为range;如果使用idx2,则类型为ref;当要扫描的行数,使用idx2大约是idx1的5倍或更多时,将使用idx1,否则使用idx2。ExtraUsingfilesort:MySQL需要额外的传递来确定如何按排序顺序检索行。排序是通过根据连接类型遍历所有行并为匹配WHERE子句的所有行保存排序键和行指针来完成的。然后对关键字进行排序,按照排序后的顺序检索行;使用临时表:使用临时表保存中间结果,性能特别差,需要优化;Usingindex:表示对应的select操作使用覆盖索引(CoveingIndex),避免访问表的数据行,效率好!如果同时出现usingwhere,说明不能通过索引搜索直接查询到符合条件的数据;Usingindexcondition:MySQL5.6后加入的ICP,usingindexcondition是利用ICP(indexpushdown),在存储引擎层进行数据过滤,而不是在服务层过滤,利用索引已有的数据来减少返回表的数据。3.showprofile分析了解SQL执行线程的状态和消耗时间。默认是关闭的,打开语句“setprofiling=1;”显示个人资料;显示查询#{id}的个人资料;4.tracetrace分析优化器如何选择执行计划。通过trace文件,可以进一步理解优惠券为什么选择A执行计划,而不是选择B执行计划。setoptimizer_trace="enabled=on";setoptimizer_trace_max_mem_size=1000000;select*frominformation_schema.optimizer_trace;5.确定问题并采取相应措施优化指标;优化SQL语句:修改SQL,IN查询切分,时间查询切分,基于上次数据过滤;使用其他实现方式:ES、数据仓库等;数据分片处理。三、场景分析1、最左匹配1)IndexKEY`idx_shopid_orderno`(`shop_id`,`order_no`)2)SQL语句select*from_twhereorderno=''从左到右查询匹配,使用order_no去Index,查询条件必须携带shop_id或index(shop_id,order_no)来切换前后顺序。2.隐式转换1)IndexKEY`idx_mobile`(`mobile`)2)SQL语句select*from_userwheremobile=12345678901隐式转换相当于对索引进行操作,会使索引失效。mobile是字符类型,使用的是数字,所以要使用字符串匹配,否则MySQL会使用隐式替换,导致索引失败。3.大分页1)IndexKEY`idx_a_b_c`(`a`,`b`,`c`)2)SQL语句select*from_twherea=1andb=2orderbycdesclimit10000,10;对于大分页的场景,可以优先考虑产品优化需求。如果不做优化,有如下两种优化方式:一种是把上次的最后一条数据,也就是上面的c,然后做"c'2021-01-0100:00:00'和order_status=10范围查询也有“IN,between”。6.ICPselect*from_orderwhereshop_id=1andorder_statusnotin(1,2)select*from_orderwhereshop_id=1andorder_status!=1ontheindexforquicksearchnotequalornotcontainingtheindex,避免使用NOT,!=,<>,!<,!>,NOTEXISTS,NOTIN,NOTLIKE,etc.7.优化器选择不使用索引。如果访问的数据量较小,优化器还是会选择辅助索引,但是当访问的数据占整个表数据的比例较大时(通常是20%左右),优化器会选择看辅助索引通过聚簇索引上行数据。select*from_orderwhereorder_status=1查询所有未支付的订单,一般这样的订单很少,即使建了索引也无法使用索引。8.复杂查询selectsum(amt)from_twherea=1andbin(1,2,3)andc>'2020-01-01';select*from_twherea=1andbin(1,2,3)andc>'2020-01-01'limit10;如果是统计某些数据,可以使用数据仓库来解决;如果是业务中这么复杂的查询,可能不建议继续使用SQL,而是使用其他方法来解决,比如使用ES来解决。9、asc和desc混用select*from_twherea=1orderbybdesc,cascdesc和asc混用时,索引会失效。10、大数据对于推送业务的数据存储,数据量可能很大。如果选择方案,最终会选择存储在MySQL上,保存有效期为7天。然后需要注意的是,频繁清理数据会导致数据碎片化,需要联系DBA进行数据碎片化处理。参考资料深入浅出MySQL:数据库开发、优化、管理和维护(唐汉明/翟振兴/关宝军/王洪全)MySQL技术内幕-InnoDB存储引擎(姜成耀)https://dev.mysql.com/doc/ref...https://dev.mysql.com/doc/ref...https://www.yuque.com/docs/sh...近期热点文章推荐:1.1,000+Java面试题及答案(2022最新版)2.劲爆!Java协程来了。..3.SpringBoot2.x教程,太全面了!4.不要用爆破爆满画面,试试装饰者模式,这才是优雅的方式!!5.《Java开发手册(嵩山版)》最新发布,赶快下载吧!感觉不错,别忘了点赞+转发!