2017 年,网络优化班的学生问怎么优化以下语句。
select rownum as r, a.*from (select npai.AREA_ID,npai.PSO_ID,npai.RO_ID,npai.NO,npai.ADDR,to_char(npai.CRTD_DT, 'yyyy-mm-dd hH24:mi:ss') as CRTD_DT,to_char(npai.CMPLT_DT, 'yyyy-mm-dd hH24:mi:ss') as CMPLT_DT,npai.CRM_PROD_ID,npai.PROD_SERV_SPEC_ID,npai.PROD_SERV_SPEC_NAME,npai.ACTION_TP_ID,npai.ACTION_TP_NAMEfrom NT_PSO_ARCH_INFO npaiwhere npai.crtd_dt >= to_date('2017-01-01', 'yyyy-mm-dd')and npai.crtd_dt <= to_date('2017-02-01', 'yyyy-mm-dd')and local_area_id = 3order by crtd_dt) awhere rownum <= 20;
执行计划如下。
Plan hash value: 2467293374-------------------------------------------------------------------------------------| Id |Operation |Name |Rows |Bytes|Cost(%CPU)|-------------------------------------------------------------------------------------| 0 |SELECT STATEMENT | | 20|28160| 489K (1)||* 1 | COUNT STOPKEY | | | | || 2 | VIEW | | 950K|1276M| 489K (1)||* 3 | SORT ORDER BY STOPKEY | | 950K| 85M| 489K (1)|| 4 | PARTITION LIST SINGLE | | 950K| 85M| 469K (1)|| 5 | TABLE ACCESS BY LOCAL INDEX ROWID|NT_PSO_ARCH_INFO| 950K| 85M| 469K (1)||* 6 | INDEX RANGE SCAN |IDX_NTPAI_CRDT | 950K| | 2581 (1)|-------------------------------------------------------------------------------------Predicate Information (identified by operation id):---------------------------------------------------1 - filter(ROWNUM<=20)3 - filter(ROWNUM<=20)6 - access("NPAI"."CRTD_DT">=TO_DATE(' 2017-01-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss')AND "NPAI"."CRTD_DT"<=TO_DATE('2017-02-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
该 SQL 类似分页语句。拿到分页语句,我们应该先查看分页语句是否符合分页编码规范。这里,SQL 完全符合分页语句编码规范。
该 SQL 排序列是 crtd_dt,执行计划中走的也是 crtd_dt 列的索引。表 nt_pso_arch_info 是 LIST 分区表,分区列是 local_area_id,从执行计划中(Id=4)看到只扫描了一个分区。按道理该 SQL 不应该出现 SORT ORDER BY。为什么执行计划中有 SORT ORDER BY 呢?我们注意观察,SQL 语句中 order by 的列 crtd_dt 在 select 中进行了 to_char 格式化,格式化之后取了别名,但是别名居然与列名一样。正是因为别名与列名一样,才导致无法消除 SORT ORDER BY。
现在我们另外取一个别名(CRTD_DT1)。
select rownum as r, a.*from (select npai.AREA_ID,npai.PSO_ID,npai.RO_ID,npai.NO,npai.ADDR,to_char(npai.CRTD_DT, 'yyyy-mm-dd hH24:mi:ss') as CRTD_DT1,to_char(npai.CMPLT_DT, 'yyyy-mm-dd hH24:mi:ss') as CMPLT_DT,npai.CRM_PROD_ID,npai.PROD_SERV_SPEC_ID,npai.PROD_SERV_SPEC_NAME,npai.ACTION_TP_ID,npai.ACTION_TP_NAMEfrom NT_PSO_ARCH_INFO npaiwhere npai.crtd_dt >= to_date('2017-01-01', 'yyyy-mm-dd')and npai.crtd_dt <= to_date('2017-02-01', 'yyyy-mm-dd')and local_area_id = 3order by crtd_dt) awhere rownum <= 20;
我们再次查看执行计划。
Plan hash value: 3066843972-------------------------------------------------------------------------------------| Id |Operation |Name |Rows |Bytes| Cost(%CPU)|-------------------------------------------------------------------------------------| 0 |SELECT STATEMENT | | 20|28160| 489K (1)||* 1 | COUNT STOPKEY | | | | || 2 | VIEW | | 950K|1276M| 489K (1)|| 3 | PARTITION LIST SINGLE | | 950K| 85M| 469K (1)|| 4 | TABLE ACCESS BY LOCAL INDEX ROWID|NT_PSO_ARCH_INFO| 950K| 85M| 469K (1)||* 5 | INDEX RANGE SCAN |IDX_NTPAI_CRDT 950K| | 2581 (1)|-------------------------------------------------------------------------------------Predicate Information (identified by operation id):---------------------------------------------------1 - filter(ROWNUM<=20)5 - access("NPAI"."CRTD_DT">=TO_DATE(' 2017-01-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND"NPAI"."CRTD_DT"<=TO_DATE(' 2017-02-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
更改别名之后,消除了 SORT ORDER BY,从而达到了优化目的。为什么必须要更改别名呢?这是因为如果不更改别名,order by crtd_dt 就相当于 order by 别名,也就是 order by to_char (npai.CRTD_DT, ‘yyyy-mm-dd hH24:mi:ss’),而索引中记录的是 date 类型,现在排序变成了按照 char 类型排序,如果不更改别名执行计划就无法消除 SORT ORDER BY。
