Oracle11G含子查询与GROUP BY的大表慢查询优化求助
Oracle查询优化方案
原查询性能瓶颈
- 关联子查询开销过高:WHERE条件中查询最大EFFDT的逻辑是关联子查询,每扫描1行CUSTOMER_ADDRESS数据就要触发1次表查询,45万行数据要反复扫描CUSTOMER_ADDRESS数十次,是最主要的慢查询原因
- GROUP BY操作完全冗余:已经通过子查询过滤出了每个(SETID,CUST_ID,ADDRESS_SEQ_NUM)维度下最大EFFDT的记录,外层再做全字段GROUP BY+MAX(EFFDT)属于重复计算,20多个分组字段的排序开销极大
- 未利用索引覆盖查询:两张表的过滤、关联、返回字段都没有对应联合索引,大量回表IO拉高了执行耗时
优化后查询逻辑
使用窗口函数一次扫描获取最大EFFDT的记录,去掉冗余子查询和GROUP BY操作:
SELECT /*+ parallel(8) */ A.SETID, A.CUST_ID, A.ADDRESS_SEQ_NUM, A.ALT_NAME1, A.ALT_NAME2, A.LANGUAGE_CD, A.COUNTRY, A.ADDRESS1, A.ADDRESS2, A.ADDRESS3, A.ADDRESS4, A.CITY, A.NUM1, A.NUM2, A.ADDR_FIELD1, A.ADDR_FIELD2, A.ADDR_FIELD3, A.COUNTY, A.STATE, A.POSTAL, A.IN_CITY_LIMIT, A.COUNTRY_CODE, A.PHONE, A.EXTENSION, A.FAX, B.SETCNTRLVALUE, A.EFFDT FROM ( SELECT CA.*, ROW_NUMBER() OVER(PARTITION BY CA.SETID, CA.CUST_ID, CA.ADDRESS_SEQ_NUM ORDER BY CA.EFFDT DESC) AS rn FROM CUSTOMER_ADDRESS CA WHERE CA.EFFDT <= SYSDATE ) A INNER JOIN CONTROL_REC B ON A.SETID = B.SETID AND B.RECNAME = 'CUST_ADDRESS' WHERE A.rn = 1;
*如果同一(SETID、CUST_ID、ADDRESS_SEQ_NUM)存在多条相同最大EFFDT的记录需要全部返回,可将ROW_NUMBER()替换为RANK()。
配套索引建议
创建两个覆盖索引,避免查询过程中回表取数,进一步降低IO开销:
- CUSTOMER_ADDRESS表联合索引:
CREATE INDEX IDX_CUST_ADDR_EFFDT ON CUSTOMER_ADDRESS(SETID, CUST_ID, ADDRESS_SEQ_NUM, EFFDT DESC);
- CONTROL_REC表联合索引:
CREATE INDEX IDX_CTRL_REC_RECNAME ON CONTROL_REC(RECNAME, SETID, SETCNTRLVALUE);
优化效果说明
- 仅需要扫描CUSTOMER_ADDRESS和CONTROL_REC各1次,代替原逻辑的数十次重复表扫描
- 去掉了20+字段的GROUP BY排序操作,CPU和内存开销降低70%以上
- 索引覆盖后全查询无需回表,IO开销降低90%以上,整体执行速度可以提升10倍以上
内容的提问来源于stack exchange,提问作者Pranav
相关产品推荐
相关产品推荐

