【问题标题】:Perfomance issues just on production database仅在生产数据库上的性能问题
【发布时间】: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


【解决方案1】:

Test 数据库索引属性包括 IOT_REDUNDANT_PKEY_ELIM 和 DROPPED 列,但不包括生产索引。这些列是在 oracle 10g 中添加的。

可能是生产数据库在旧的 9i 版本下运行,而测试数据库在 10g 下运行?如果是这样,我认为这是比其他任何事情都更重要的区别。

也就是说,如果“select count(*) from thetable”没有使用主键索引,那就很奇怪了。索引统计数据非常过时(14,004,395 行,当您建议有超过 3000 万且上次收集是在 3 月时)。如果表格在过去六个月中翻了一番,并且其统计数据更早,那么这可能是个问题。

【讨论】:

    【解决方案2】:

    生产的自动跟踪计划显示“规则”优化器。如果您查看Oracle Tuning document (9i) 部分 RBO 路径 15:全表扫描,它清楚地表明将使用全表扫描。

    【讨论】:

    • 我尝试将模式优化器模式更改为 CHOOSE,但仍然很慢。
    • 你能提供自动跟踪输出吗?
    • 那里。这个简单的查询花了将近 2 分钟!
    • Oracle db 版本差异分开 (@Gary) 索引统计的真正问题是 CLUSTERING_FACTOR (Test=611494, Production=10154395)。您可以尝试在生产环境中重建索引并查看 stat 的变化。
    • 聚簇因子不依赖于索引,它依赖于表,所以除非你重新组织表中的数据,否则不会改变聚簇因子。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-21
    • 2022-01-03
    • 1970-01-01
    • 2013-06-15
    • 2019-12-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多