日期:2014-05-16  浏览次数:20524 次

复合索引【复合索引顺序选择问题】
复合索引第一个原则:前缀性(Prefixing)

复合索引的前缀性是指只有当复合索引的第一个字段出现在SQL语句的谓词条件中时,该索引才会被用到。
如复合索引为(ename,job,mgr),只要谓词条件中出现第一个字段ename,就可以用复合索引,否则不会用。
唯一的例外是skip scan index,就是如果Oracle发现第一个字段的值很少,会自动拆分为两个复合索引。如复合索引(gender,ename,job,mgr),因为第一个字段gender只有两个值:男和女,因此Oracle会将这个索引拆分成('男',ename,job,mgr)和('女',ename,job,mgr)两个复合索引,这样即使gender没有出现在谓词条件中,也可以用该复合索引。

skip scan是Oracle针对特定条件上索引结构,所提供的一种备选搜索操作。Skip scan的使用不是规则,而是成本估算。Index Skip Scan是Oracle提供的一种执行计划操作,可以应用在执行计划的生成中。简单的说,就是Oracle将SQL描述语句转化为可执行操作序列(执行计划)过程中一个操作选择。



复合索引第二个规则:可选性(Selectivity)

Oracle建议复合索引应按字段可选性(即值的多少)的高低进行排列,这是因为,字段值越多,可选性越强,定位的记录就越少,查询效率就越高。




========================

我先从底层看起。好老的环境哦,还是Oracle 8.0.6。硬件配置还可以,IBM RS6000机器,4CPU/2G。你才上海一个区的数据嘛,才几个G,处理能力肯定没问题。再看数据库参数,乖乖,从未调过啊。这不相当于把奔驰车常年挂在一档开吗?调参数很简单,但Oracle 8.0.6需要重新启动,白天业务期间无法做。只好看应用了,当然也是我期待已久的。8.0.6在性能分析方面比较土,只能用蹩脚的utlbstat,utlestat脚本,或者直接去视图里分析。我当然不会象前面的洋‘忽悠’一样,去查询内部视图,况且我一个人呆在黑古隆冬的机房里,想做秀也没人看啊。还是那句话,发现问题并不难,难得是分析和解决问题。喏,以下就是当时在10:00多业务高峰时的一些最消耗资源的语句:



BEGIN htjs.FP_QMKCJZ_T(:1,:2,:3); END


SELECT COUNT(*) FROM HTJS.FP_QYLYC WHERE NSRSBH = :b1 AND YF = :2 AND SFLB != 'S';


SELECT FP_DM, QS_HM,FP_SL FROM HTJS.FP_QYLYC WHERE YF=:b1 and SFLB = 'S'  and FP_ZL = 's' and NSRSBH = :b2;


SELECT SWJG_DM,FP_DM,FP_QS_HM,FP_SL,SFLB   FROM HTJS.FP_SFD  WHERE TO_CHAR(SFRQ,'YYYYMM') = TO_CHAR(:b1)  AND NSRSBH = :b2  AND (SFLB = '12'  OR SFLB = '21' ) AND OLDFLAG = '0' ORDER BY ID;


SELECT MAX(BSYF)   FROM HTJS.CB_QY_BSQK_TJB  WHERE NSRSBH = :b1;



以上述第2,3条SQL语句为例,当时系统已经在HTJS.FP_QYLYC表的如下字段上按顺序建立了一个复合索引:



YF                     ----- 月份

SWJG_DM                ----- 税务机关_代码

NSRSBH                 ----- 纳税人识别号

FP_DM                  ----- 发票_代码

SFLB                   ----- 收费类别

QS_HM                  ----- XX_号码



看出问题了吧?虽然两条语句都含YF(月份)字段,符合前缀性原则,但Oracle实际上没有使用该索引,因为同一月份记录太多了,还不如全表扫描。更重要的是,该复合索引的字段顺序的设计上根本没有考虑各字段的可选性。于是,我当时新建了一个索引:create index ora_FP_QYLYC_2 on FP_QYLYC(NSRSBH ,YF,SFLB,FP_ZL) tablespace fpfs;

===========

效果评估:

前端应用软件反应速度由30秒下降为不足1秒。

CPU平均利用率由50%下降为5%。

I/O量急剧下降。

上述语句从最消耗资源的语句列表中消失。