当前位置: 首页 > 科技观察

SQL性能优化策略之索引优化方法

时间:2023-03-21 16:54:34 科技观察

SQL优化是优化工作中经常涉及到的一个问题,因为早期的开发人员往往只关注SQL功能的实现,而忽略了性能。尤其是复杂的SQL,上线后很少修改。一旦出现问题,即使是最初的开发人员自己也很难梳理出业务逻辑。理解代码之间的关系需要花费很多时间。无从下手。因此,开发者应该在前期做好代码注释,避免写出过于复杂的SQL语句。本文介绍一些真实的生产环境中常用的索引优化方法。当遇到SQL问题时,可以使用不同的工具(PL/SQL、TOAD等)awrsqrpt或dbms_xplan获取SQL的详细执行计划和资源消耗信息。业务案例中的SQL语句如下:SQL>selectsum(cggzl)cggzl,sum(qbgzl)qbgzlfrom(selectcasewhenzlxm_mclike'%2ê3?3¥1??ì2é%'thengzlelse0endcggzl,casewhenzlxm_mclike'%?3±í?÷1ù%'thengzlelse0endqbgzlfromdictmanage.dict_zl_prob,his.pat_inpat_order_infoc,pat_inpat_order_costdwhered.sfxm_id=b.zlxm_idandc.yzjl_id=d.dyzy_yzjl_idandzlxm_mclike'%2???%'andc.yz_zxrq>=to_date(sysdate)andc.yz_zxrq0andc.yz_zfrqisnullandc.zylsh=:in_zylsh)SQL的详细执行计划如图1所示。图1 SQL执行计划AWR报告资源消耗信息展示在图2中。图2 AWR报表中的AWR资源消耗信息上面代码所示的业务SQL语句通过三张表进行关联,最终返回的行数为个位数。从执行计划中可以看出,Id=0,CBO计算出的总COST为123K,其中大部分COST是对Id=10的表pat_inpat_order_cost进行全表扫描产生的。此时,我们需要重点关注pat_inpat_order_cost与另外两张表的关系。在where条件中,除了pat_inpat_order_cost的sfxm_id和dyzy_yzjl_id与其他两张表的字段关联外,只有fy_status一个过滤条件。我们看列的选择性如下:SQL>select/*+NO_MERGELEADING(ab)*/b.owner,b.table_name,a.column_name,b.num_rows,a.num_distinctCardinality,ROUND(A.num_distinct*100/B.num_rows,1)selectivityfromdba_tab_col_statisticsa,dba_tablesbwherea.owner=b.owneranda.table_name=b.table_nameanda.owner=upper('his')and.table_name=upper('pat_inpat_order_cost')anda.column_name=upper('fy_status');pat_inpat_order_cost表的字段信息如图3所示。图3 pat_inpat_order_cost表字段信息SQL>selectcount(*),FY_STATUSfromhis.pat_inpat_order_costcgroupbyFY_STATUS;fy_status字段列的选择性如图4所示。图4 fy_status字段列的选择性从图4可以看出,fy_status的选择性并不好,存在严重的偏斜。语句中的固定写法d.fy_statusin('1','2')几乎包含所有记录,所以不是一个好的过滤器。where条件中的过滤条件大部分来自C表pat_inpat_order_info,C表与D表pat_inpat_order_cost的sfxm_id字段相关联。整个SQL语句返回的行数是个位数。通过YZ_ZXRQ_IDX索引范围扫描C表,然后回表过滤得到绑定变量的值,然后进一步确认C表返回的行数,代码如下:SQL>selectsql_Id,name,datatype_string,last_captured,value_stringfromv$sql_bind_capturewheresql_id='18rwad2bgcxfa';SQL绑定变量值的获取如图5所示。图5 SQL绑定变量值获取SQL>selectcount(*)fromhis.pat_inpat_order_infocwherec.yz_zxrq>=to_date(sysdate)andc.yz_zxrqcreateindexIDX_SFXM_IDonPAT_INPAT_ORDER_COST(SFXM_ID);Planhashvalue:408580053---------------------------------------------------------------------------------------------------|Id|Operation|Name|Rows|字节|成本(%CPU)|时间|--------------------------------------------------------------------------------------------|0|SELECTSTATEMENT||||12(100)|||1|SORTAGGREGATE||1|68|||*2|FILTER|||||||3|NESTEDLOOPS||1|68|12(0)|00:00:01||4|嵌套||1|68|12(0)|00:00:01||5|嵌套||1|39|11(0)|00:00:01||*6|TABLEACCESSBYGLOBALINDEXROWID|PAT_INPAT_ORDER_INFO|1|21|5(0)|00:00:01||*7|INDEXRANGESCAN|YZ_ZXRQ_IDX|4||3(0)|00:00:01||*8|表访问BYGLOBALINDEXROWID|PAT_INPAT_ORDER_COST|6|108|6(0)|00:00:01||*9|INDEXRANGESCAN|IDX_DYZY_YZJL_ID|6||2(0)|00:00:01||*10|INDEXUNIQUESCAN|DICT_ZL_PRO_PK|1||0(0)|||*11|TABLEACCESSBYINDEXROWID|DICT_ZL_PRO|1|29|1(0)|00:00:01|--------------------------------------------------------------------------------------------PredicateInformation(identifiedbyoperationid):--------------------------------------------------2-过滤器(TO_DATE(TO_CHAR(SYSDATE@!+1))>TO_DATE(TO_CHAR(SYSDATE@!)))6-filter(("C"."ZYLSH"=TO_NUMBER(:IN_ZYLSH)AND"C"."YZ_ZFRQ"ISNULL))7-access("C"."YZ_ZXRQ">=TO_DATE(TO_CHAR(SYSDATE@!))AND"C"."YZ_ZXRQ"0ANDINTERNAL_FUNCTION("D"."FY_STATUS")))9-access("C"."YZJL_ID"="D"."DYZY_YZJL_ID")10-access("D"."SFXM_ID"="B"."ZLXM_ID")11-filter("ZLXM_MC"LIKE'%part%')创建索引后,整个执行计划按照我们想象的方式进行,SQL执行时间从原来的24分钟缩短到1秒,速度提高了。千百次以上案例介绍了最简单的SQL优化方法。在大多数情况下,开发人员很难对应用进行修改,因此索引优化在SQL优化中显得尤为重要。本文节选自《DBA攻坚指南:左手Oracle,右手MySQL》,经出版社授权发布。

最新推荐
猜你喜欢