SQL优化一则:灵活运用字段的选择性

概念:

 

优化策略:字段选择性

 

  • 选择性较低索引 可能带来的性能问题

  • 索引选择性=索引列唯一值/表记录数;

  • 选择性越高索引检索价值越高,消耗系统资源越少;选择性越低索引检索价值越低,消耗系统资源越多;

  • 查询条件含有多个字段时,不要在选择性很低字段上创建索引

  • 可通过创建组合索引来增强低字段选择性和避免选择性很低字段创建索引带来副作用;

  • 尽量减少possible_keys,正确索引会提高sql查询速度,过多索引会增加优化器选择索引的代价,不要滥用索引;

 

现象:

昨天数据库一个SQL在读库上占用很高的CPUCPU一直在100%CPU wait达到100多,通EMSQL监视 可以看到,有一条SQl在多次执行时一直没有完成,有的运行20多分钟还在执行。

 

SQL如下:

Select DistinctFppolicyin0_.Id                 AsId53_,
                                     Fppolicyin0_.Carrier_Code       As Carrier2_53_,
                                     Fppolicyin0_.Policy_Id          As Policy3_53_,
                                     Fppolicyin0_.Carrier_Policyid   As Carrier4_53_,
                                     Fppolicyin0_.Agent_Id           As Agent5_53_,
                                     Fppolicyin0_.Airline            As Airline53_,
                                     Fppolicyin0_.Airline_Type       As Airline7_53_,
                                     Fppolicyin0_.Apply_Flightnos    As Apply8_53_,
                                     Fppolicyin0_.Exc_Flightnos      As Exc9_53_,
                                     Fppolicyin0_.Class_Codes        As Class10_53_,
                                     Fppolicyin0_.Shortstay_Time     As Shortstay11_53_,
                                     Fppolicyin0_.Useweek            As Useweek53_,
                                     Fppolicyin0_.Tkt_Type           As Tkt13_53_,
                                     Fppolicyin0_.Psg_Type           As Psg14_53_,
                                     Fppolicyin0_.Is_Special         As Is15_53_,
                                     Fppolicyin0_.Is_Commend         As Is16_53_,
                                     Fppolicyin0_.Limit_Code         As Limit17_53_,
                                     Fppolicyin0_.Pre_Outtkt_Day     As Pre18_53_,
                                     Fppolicyin0_.Last_Outtkt_Day    As Last19_53_,
                                     Fppolicyin0_.Flight_Price       As Flight20_53_,
                                     Fppolicyin0_.Rebate             As Rebate53_,
                                     Fppolicyin0_.Flight_Price_Chd   As Flight22_53_,
                                     Fppolicyin0_.Rebate_Chd         As Rebate23_53_,
                                     Fppolicyin0_.Flight_Price_Um    As Flight24_53_,
                                     Fppolicyin0_.Rebate_Um          As Rebate25_53_,
                                     Fppolicyin0_.Flight_Price_Inf   As Flight26_53_,
                                     Fppolicyin0_.Rebate_Inf         As Rebate27_53_,
                                     Fppolicyin0_.Out_Tktcity        As Out28_53_,
                                     Fppolicyin0_.Ei                 As Ei53_,
                                     Fppolicyin0_.Signticket         As Signticket53_,
                                     Fppolicyin0_.Endorsement        As Endorse31_53_,
                                     Fppolicyin0_.Refundmemo         As Refundmemo53_,
                                     Fppolicyin0_.Enei               As Enei53_,
                                     Fppolicyin0_.Enendorsement      As Enendor34_53_,
                                     Fppolicyin0_.Enrefundmemo       As Enrefun35_53_,
                                     Fppolicyin0_.Tkt_Startdate      AsTkt36_53_,
                                     Fppolicyin0_.Tkt_Enddate        As Tkt37_53_,
                                     Fppolicyin0_.Tkt_Useweek        As Tkt38_53_,
                                     Fppolicyin0_.Fp_Startdate       As Fp39_53_,
                                     Fppolicyin0_.Fp_Enddate         As Fp40_53_,
                                     Fppolicyin0_.Fp_Useweek         As Fp41_53_,
                                     Fppolicyin0_.Exc_Startdate      As Exc42_53_,
                                     Fppolicyin0_.Exc_Enddate        As Exc43_53_,
                                     Fppolicyin0_.Is_Open            As Is44_53_,
                                     Fppolicyin0_.Ret_Startdates     As Ret45_53_,
                                     Fppolicyin0_.Ret_Enddates       As Ret46_53_,
                                     Fppolicyin0_.Mf_Remark          As Mf47_53_,
                                     Fppolicyin0_.Remark             As Remark53_,
                                     Fppolicyin0_.Create_Date        As Create49_53_,
                                     Fppolicyin0_.Longstay_Time      As Longstay50_53_,
                                     Fppolicyin0_.Levcity            As Levcity53_,
                                     Fppolicyin0_.Arvcity            As Arvcity53_,
                                     Fppolicyin0_.Levdrome           As Levdrome53_,
                                     Fppolicyin0_.Arvdrome           As Arvdrome53_,
                                     Fppolicyin0_.Is_To_Pata         As Is55_53_,
                                     Fppolicyin0_.Commend_Rmk        As Commend56_53_,
                                     Fppolicyin0_.Isgroup            As Isgroup53_,
                                     Fppolicyin0_.Policy_Source      As Policy58_53_,
                                     Fppolicyin0_.Tkt_Price          As Tkt59_53_,
                                     Fppolicyin0_.Other_Segment      As Other60_53_,
                                     Fppolicyin0_.Spe_Display_Name   As Spe61_53_,
                                     Fppolicyin0_.Fp_Startdate_Back  As Fp62_53_,
                                     Fppolicyin0_.Fp_Enddate_Back    As Fp63_53_,
                                     Fppolicyin0_.Exc_Startdate_BackAs Exc64_53_,
                                     Fppolicyin0_.Exc_Enddate_Back   As Exc65_53_,
                                     Fppolicyin0_.Fp_Starttime       As Fp66_53_,
                                     Fppolicyin0_.Fp_Endtime         As Fp67_53_,
                                     Fppolicyin0_.Fp_Starttime_Back  As Fp68_53_,
                                     Fppolicyin0_.Fp_Endtime_Back    As Fp69_53_
     From Fp_Policyinfo_Dt   Fppolicyin0_,
               Code_Airways       Tkcodeairw1_,
               Fp_Policy_Issue_Dt Fppolicyis2_,
               Code_Airdrome      Tkcodeaird3_,
               Code_Airdrome      Tkcodeaird4_,
               Fp_Policy_Issue_Dt Fppolicyis5_
 Where Fppolicyin0_.Policy_Id =Fppolicyis5_.Id
      And
1 = 1
      And Fppolicyis5_.Status =
'1'
      And Fppolicyin0_.Carrier_Code =Tkcodeairw1_.Id
      And Fppolicyin0_.Policy_Id =Fppolicyis2_.Id
      And (Fppolicyin0_.Levdrome =Tkcodeaird3_.Airdromeid Or
               Fppolicyin0_.Levdrome =
'*')
      And (Fppolicyin0_.Arvdrome =Tkcodeaird4_.Airdromeid Or
               Fppolicyin0_.Arvdrome =
'*')
      And ((Fppolicyin0_.Levcity =
'PEK' Or --变量1
               Fppolicyin0_.Levcity =
               (Select Tkcodeaird6_.Cityid
                            FromCode_Airdrome Tkcodeaird6_
                         WhereTkcodeaird6_.Airdromeid =
'PEK')) And --变量2
               (Fppolicyin0_.Arvcity =
'SHA' Or --变量3
               Fppolicyin0_.Arvcity =
               (Select Tkcodeaird7_.Cityid
                            FromCode_Airdrome Tkcodeaird7_
                        Where Tkcodeaird7_.Airdromeid =
'SHA')) Or --变量4
               Fppolicyin0_.Airline =
'*-*')
      And (Fppolicyin0_.Policy_Source IsNull Or
               Fppolicyin0_.Policy_Source <>
'P')
      And (Fppolicyin0_.Tkt_Startdate IsNull Or
               Fppolicyin0_.Tkt_Startdate <=
'2016-03-17') --变量5
      And (Fppolicyin0_.Tkt_Enddate IsNull Or
               Fppolicyin0_.Tkt_Enddate >=
'2016-03-17') --变量6

 

分析解决:

通过和开发人员沟通,此SQL是航班查询的功能。

 

查看SQL的执行计划,发现cost值非常大:

 

查看SQL中相关的的5个表,其中Fp_Policyinfo_Dt FP_POLICY_ISSUE_DT表数据量最大,记录数达900多万行,应该是没使用正确的索引导致的SQL查询慢。

首先考虑是否有索引碎片,尝试重建几个比较大的索引无效

接着尝试新建某些索引也无效

 

再次研究发现Fp_Policy_Issue_Dt表中Status字段值(1)SQL中是写死的,于是查看Status字段在表中的分布

 

--查看字段值分布

SQL> Select status,Count(1) FromFP_POLICY_ISSUE_DT group by cube(status);

 

STATUS      COUNT(1)

---------- ----------

              9663424 --总记录数

0                1200

1              586632

2               13730

3             9061862

 

--查看status值为1的占总记录数的比例

SQL> select round(586632/9663424,2) fromdual;

 

ROUND(586632/9663424,2)

-----------------------

                   0.06

SQL> select round(586632/9663424,2) fromdual;

 

ROUND(586632/9663424,2)

-----------------------

                   0.06

 

可以看到STATUS=3的为绝大多数,status=1只占6%,所以在status上字段创建索引,在SQL查询status=1时,可以提高SQL索引的选择性,使SQL查询效率会更高。

 

--下面我们尝试创建索引

SQL> reate index ind_IDX_ FP_POLICY_ISSUE_STATUSon FP_POLICY_ISSUE_DT (status) online;

 

--再查看执行计划

 

可以看到SQl使用了我们新建的索引IDX_ FP_POLICY_ISSUE_STATUSSQL的执行时间也由原来的30分钟以上,优化后6秒就能出来了。

 

总结:

按常规来说,像状态类型等这类选择性比较低的字段是不适合建立索引的,但在实际情况中,我们要充分了所查字段值的分布情况,在SQL查询中要根据字段值实际分布建立合适的索引,灵活使用索引的选择性,也提高SQL的查询性能。

 

内容参考:http://www.cnblogs.com/zhengyun_ustc/p/slowquery2.html

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值