【发布时间】:2011-04-09 21:38:20
【问题描述】:
我在查询生产数据库中的表时遇到了一些性能问题。虽然查询在测试数据库中运行时间为 2.1 秒(返回 2800 万条记录中的 8640 条),但在生产中,它需要 2.05 分钟(返回 3100 万条记录中的 8640 条)。由于我不是甲骨文专家,因此我很难找到问题所在。 由于两个数据库中的解释计划都显示了正确的索引使用情况,我倾向于认为问题出在表/索引的创建上。 我注意到用于创建表的 SQL 脚本之间存在一些细微差别:
测试数据库:
create table TB_PONTO_ENE
(
cd_ponto NUMBER(10) not null,
cd_fonte NUMBER(10),
cd_medidor NUMBER(10),
cd_usuario NUMBER(10),
dt_hr_insercao DATE,
dt_hr_instante DATE not null,
dt_hr_hora DATE,
dt_hr_dia DATE,
dt_hr_mes DATE,
dt_hr_instante_hv DATE,
dt_hr_hora_hv DATE,
dt_hr_dia_hv DATE,
dt_hr_mes_hv DATE,
vl_eneat_del FLOAT,
vl_eneat_rec FLOAT,
vl_enere_del FLOAT,
vl_enere_rec FLOAT,
vl_eneat_del_cp FLOAT,
vl_eneat_rec_cp FLOAT,
vl_enere_del_cp FLOAT,
vl_enere_rec_cp FLOAT
)
tablespace TELEMEDICAO
pctfree 10
initrans 1
maxtrans 255
storage
(
initial 64K
minextents 1
maxextents unlimited
);
alter table TB_PONTO_ENE
add constraint CP_TB_PONTO_ENE primary key (CD_PONTO, DT_HR_INSTANTE)
using index
tablespace TELEMEDICAO
pctfree 10
initrans 2
maxtrans 255
storage
(
initial 64K
minextents 1
maxextents unlimited
);
alter table TB_PONTO_ENE
add constraint CE_PENE_CD_FONTE foreign key (CD_FONTE)
references TB_FONTE (CD_FONTE) on delete set null;
alter table TB_PONTO_ENE
add constraint CE_PENE_CD_MEDIDOR foreign key (CD_MEDIDOR)
references TB_MEDIDOR (CD_MEDIDOR) on delete set null;
alter table TB_PONTO_ENE
add constraint CE_PENE_CD_PONTO foreign key (CD_PONTO)
references TB_PONTO (CD_PONTO) on delete cascade;
alter table TB_PONTO_ENE
add constraint CE_PENE_CD_USUARIO foreign key (CD_USUARIO)
references TB_USUARIO (CD_USUARIO) on delete set null
disable;
生产数据库:
create table TB_PONTO_ENE
(
cd_ponto NUMBER(10) not null,
cd_fonte NUMBER(10),
cd_medidor NUMBER(10),
cd_usuario NUMBER(10),
dt_hr_insercao DATE,
dt_hr_instante DATE not null,
dt_hr_hora DATE,
dt_hr_dia DATE,
dt_hr_mes DATE,
dt_hr_instante_hv DATE,
dt_hr_hora_hv DATE,
dt_hr_dia_hv DATE,
dt_hr_mes_hv DATE,
vl_eneat_del FLOAT,
vl_eneat_rec FLOAT,
vl_enere_del FLOAT,
vl_enere_rec FLOAT,
vl_eneat_del_cp FLOAT,
vl_eneat_rec_cp FLOAT,
vl_enere_del_cp FLOAT,
vl_enere_rec_cp FLOAT
)
tablespace TELEMEDICAO
pctfree 10
initrans 1
maxtrans 255
storage
(
initial 64K
next 5M
minextents 1
maxextents unlimited
pctincrease 0
);
alter table TB_PONTO_ENE
add constraint CP_TB_PONTO_ENE primary key (CD_PONTO, DT_HR_INSTANTE)
using index
tablespace MEDICAO_NDX
pctfree 10
initrans 2
maxtrans 255
storage
(
initial 64K
next 1M
minextents 1
maxextents unlimited
pctincrease 0
);
alter table TB_PONTO_ENE
add constraint CE_PENE_CD_FONTE foreign key (CD_FONTE)
references TB_FONTE (CD_FONTE) on delete set null;
alter table TB_PONTO_ENE
add constraint CE_PENE_CD_MEDIDOR foreign key (CD_MEDIDOR)
references TB_MEDIDOR (CD_MEDIDOR) on delete set null;
alter table TB_PONTO_ENE
add constraint CE_PENE_CD_PONTO foreign key (CD_PONTO)
references TB_PONTO (CD_PONTO) on delete cascade;
alter table TB_PONTO_ENE
add constraint CE_PENE_CD_USUARIO foreign key (CD_USUARIO)
references TB_USUARIO (CD_USUARIO) on delete set null;
生产数据库将索引放在另一个表空间中。另一个区别是表空间声明中的next 5M(测试数据库中没有定义值)。
查看索引属性时,我也看到了一些差异:
测试数据库:
- AVG_DATA_BLOCKS_PER_KEY 1
- AVG_LEAF_BLOCKS_PER_KEY 1
- BLEVEL 2
- BUFFER_POOL默认
- CLUSTERING_FACTOR 611494
- 压缩已禁用
- 学位 1
- DISTINCT_KEYS 28568389
- 已删除否
- 已生成 N
- GLOBAL_STATS 是
- INDEX_NAME CP_TB_PONTO_ENE
- INDEX_TYPE正常
- INITIAL_EXTENT 65536
- INI_TRANS 2
- 实例 1
- IOT_REDUNDANT_PKEY_ELIM没有
- JOIN_INDEX 否
- LAST_ANALYZED 21/07/2010 22:08:34
- LEAF_BLOCKS 85809
- 日志记录是的
- MAX_EXTENTS 2147483645
- MAX_TRANS 255
- MIN_EXTENTS 1
- NUM_ROWS 28568389
- 分区否
- PCT_FREE 10
- SAMPLE_SIZE 377209
- 中学 N
- 状态有效
- TABLESPACE_NAME TELEMEDICAO
- TABLE_NAME TB_PONTO_ENE
- TABLE_TYPE 表格
- 临时 N
- 独特性 独特性
- USER_STATS 没有
生产数据库:
- AVG_DATA_BLOCKS_PER_KEY 1
- AVG_LEAF_BLOCKS_PER_KEY 1
- BLEVEL 2
- BUFFER_POOL默认
- CLUSTERING_FACTOR 10154395
- 压缩已禁用
- 学位 1
- DISTINCT_KEYS 14004395
- 已生成 N
- GLOBAL_STATS 是
- INDEX_NAME CP_TB_PONTO_ENE
- INDEX_TYPE正常
- INITIAL_EXTENT 65536
- INI_TRANS 2
- 实例 1
- JOIN_INDEX 否
- LAST_ANALYZED 05/03/2010 08:45:19
- LEAF_BLOCKS 42865
- 日志记录是的
- MAX_EXTENTS 2147483645
- MAX_TRANS 255
- MIN_EXTENTS 1
- NEXT_EXTENT 1048576
- NUM_ROWS 14004395
- 分区否
- PCT_FREE 10
- PCT_INCREASE 0
- SAMPLE_SIZE 2800879
- 中学 N
- 状态有效
- TABLESPACE_NAME MEDICAO_NDX
- TABLE_NAME TB_PONTO_ENE
- TABLE_TYPE 表格
- 临时 N
- 独特性 独特性
- USER_STATS 没有
另外两件事引起了我的注意:select count(*) from thetable 的解释计划显示该索引在测试数据库中使用,但在生产数据库中显示全表扫描。这让我发现了另一个观察结果:测试数据库索引有 160MB,而生产数据库有超过 1GB(我们不在此表上执行删除操作)。
谁能指出我的解决方案?
更新
以下是执行计划:
测试数据库:
Execution Plan
----------------------------------------------------------
Plan hash value: 1441290166
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 18767 (4)| 00:03:46 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | INDEX FAST FULL SCAN| IDX_HV_TB_PONTO_ENE | 28M| 18767 (4)| 00:03:46 |
-------------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
111 recursive calls
0 db block gets
83586 consistent gets
83533 physical reads
0 redo size
422 bytes sent via SQL*Net to client
399 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
1 rows processed
生产数据库
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=RULE
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (FULL) OF 'TB_PONTO_ENE'
Statistics
----------------------------------------------------------
1 recursive calls
3 db block gets
605327 consistent gets
603698 physical reads
180 redo size
201 bytes sent via SQL*Net to client
242 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
更新 2
生产服务器正在运行 Oracle 9.2.0。
更新 3
以下是优化器模式设置为CHOOSE 的执行统计数据:
SQL> SELECT dt_hr_instante, vl_eneat_del,vl_eneat_rec,vl_enere_del, vl_enere_rec FROM tb_ponto_ene WHERE cd_ponto = 31 AND dt_hr_instante BETWEEN to_date('01/06/2010 00:05:00','dd/mm/yyyy hh24:mi:ss') AND to_date('01/07/2010 00:00:00', 'dd/mm/yyyy hh24:mi:ss');
8640 rows selected.
Elapsed: 00:01:49.51
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=4 Card=1 Bytes=36)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'TB_PONTO_ENE' (Cost=4 Card=1 Bytes=36)
2 1 INDEX (RANGE SCAN) OF 'CP_TB_PONTO_ENE' (UNIQUE) (Cost=3 Card=1)
Statistics
----------------------------------------------------------
119 recursive calls
0 db block gets
9169 consistent gets
7438 physical reads
0 redo size
308524 bytes sent via SQL*Net to client
4267 bytes received via SQL*Net from client
577 SQL*Net roundtrips to/from client
6 sorts (memory)
0 sorts (disk)
8640 rows processed
【问题讨论】:
-
您能否通过在测试和生产中运行以下命令来显示两者的完整执行计划和统计信息:
-
(Drat!)
SET AUTOTRACE TRACEONLY;然后select count(*) from TB_PONTO_ENE ;(我怀疑生产中的索引应该合并或重建并更新统计信息,但我想查看计划和 I/O首先。) -
完成了。值得注意的是,生产服务器执行它花了将近 5 分钟
标签: performance oracle