赞
踩
案例背景:
1、客户生产环境分页查询在收集统计信息后,查询变得缓慢。
2、语句本身属于弱选择性语句。语句的访问路径,优化器选择了全表扫描+排序,在排序部分cost消耗很大。
3、语句中,排序列和条件列存在组合索引,添加索引访问hint后,发现组合索引访问的cost要高于全表扫描+排序,实际使用组合索引访问的效率要高于全表扫描+排序(索引自身是有序的)。
问题解决:
(1)、删除统计信息,优化器选择索引访问。(不是所有环境都适用)
(2)、客户反馈问题得到优化。
问题测试与分析:
1、创建测试表
- CREATE TABLE "SYSDBA"."TEST_4"
- (
- "SEQID" INT , --唯一值,作为排序
- "OWNER" VARCHAR(128),
- "OBJECT_NAME" VARCHAR(128),
- "SUBOBJECT_NAME" VARCHAR(128),
- "OBJECT_ID" DEC,
- "DATA_OBJECT_ID" VARCHAR(1),
- "OBJECT_TYPE" VARCHAR(18),
- "CREATED" TIMESTAMP(6),
- "LAST_DDL_TIME" TIMESTAMP(6),
- "TIMESTAMP" TIMESTAMP(6),
- "STATUS" VARCHAR(7), --查询列
- "TEMPORARY" VARCHAR(1),
- "GENERATED" VARCHAR(1),
- "SECONDARY" VARCHAR(1),
- "NAMESPACE" VARCHAR(1),
- "EDITION_NAME" VARCHAR(1),
- "STATUS_INI" varchar(1) --查询列
- ) STORAGE(ON "MAIN", CLUSTERBTR) ;

2、测试数据分布
select STATUS,STATUS_INI,count(*) from test_4 group by STATUS,STATUS_INI
3、创建唯一索引,组合索引
4、收集统计信息
- BEGIN
- dbms_stats.gather_table_stats(
- ownname=>'SYSDBA',
- tabname=>'TEST_4',
- cascade=>TRUE,
- estimate_percent=>100,
- method_opt=>'FOR ALL COLUMNS SIZE AUTO',--每列收集直方图
- no_invalidate=>FALSE);
- END;
- /
5、测试语句(全表扫描+排序)
使用全表扫描+排序,执行时间约12s,cost=96527
- select * from (
- select a1.*,rownum rn from (
- select t.* from test_4 t where
- status ='VALID'
- and status_ini = 'a'
- order by seqid
- )a1
- where rownum <= 1500000
- )s1
- where s1.rn > 1000000
6、测试语句(索引读)
使用索引读,执行时间约2.8s,cost=102545
- select * from (
- select a1.*,rownum rn from (
- select /*+ index(t,INDEX_TEST4_2)*/t.* from test_4 t
- where status ='VALID'
- and status_ini = 'a'
- order by seqid
- )a1
- where rownum <= 1500000
- )table_alias
- where table_alias.rn > 1000000
绑定执行计划:
1、需要绑定的sql
- select * from (
- select a1.*,rownum rn from (
- select t.* from test_4 t
- where status ='VALID'
- and status_ini = 'a'
- order by seqid
- )a1
- where rownum <= 1500000
- )table_alias
- where table_alias.rn > 1000000
2、当前执行计划
3、启用语句增加HINT
sp_set_para_value(1,'ENABLE_INJECT_HINT',1);
4、SQL语句绑定HINT
- SF_INJECT_HINT(
- 'select * from (
- select a1.*,rownum rn from (
- select t.* from test_4 t
- where status =''VALID''
- and status_ini = ''a''
- order by seqid
- )a1
- where rownum <= 1500000
- )s1
- where s1.rn > 1000000;',
- 'index(t,INDEX_TEST4_2)',
- 'index_test4',
- null,
- true,
- FALSE
- );

通过SYSINJECTHINT系统表可以查看相关信息:
select * from SYSINJECTHINT;
5、查看效果
6、删除指定的INJECTHINT规则:
SF_DEINJECT_HINT('INDEX_TEST4');
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。