0

我们有一个名为 的表t_reading,具有以下架构:

MEAS_ASS_ID     NUMBER(12,0)
READ_DATE       DATE
READ_TIME       VARCHAR2(5 BYTE)
NUMERIC_VAL     NUMBER
CHANGE_REASON   VARCHAR2(240 BYTE)
OLD_IND         NUMBER(1,0)

该表的索引如下:

CREATE INDEX RED_X4 ON T_READING
(
  "OLD_IND",
  "READ_DATE" DESC,
  "MEAS_ASS_ID",
  "READ_TIME"
)

这个确切的表(具有相同的数据)存在于两台服务器上,唯一的区别是每台服务器上安装的 Oracle 版本。

有问题的查询是:

SELECT * FROM t_reading WHERE OLD_IND = 0 AND MEAS_ASS_ID IN (5022, 5003) AND read_date BETWEEN to_date('30/10/2012', 'dd/mm/yyyy') AND to_date('31/10/2012', 'dd/mm/yyyy');

此查询在 Oracle 10 上执行不到一秒,在 Oracle 9 上执行大约一分钟。

我们错过了什么吗?

编辑:

Oracle 9 的执行计划: 在此处输入图像描述

Oracle 10 的执行计划: 在此处输入图像描述

4

4 回答 4

1

几个可能的解释:

  • 您正在范围扫描不同的索引。
  • 假设您在 10g 表上有相同的索引,但您只是将其称为不同的东西,解释计划是不同的。

我主要担心的是 9i 查询的解释计划的行、字节和成本列中缺少信息。默认情况下, Oracle 9i 不收集统计信息,此详细信息表明您尚未收集此表的统计信息。用于dbms_stats收集有关您的表和索引的统计信息。具体程序gather_table_stats

BEGIN

    DBMS_STATS.GATHER_TABLE_STATS (
       ownname => user, 
       tabname => 'T_READING', 
       estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE
       method_opt => 'FOR ALL INDEXED COLUMNS',
       cascade => TRUE, -- gather index statistics
        );
END:

如果您有兴趣,还有很多其他选择。假设索引不同,这可能有助于 CBO(假设它“打开”)选择正确的索引。

其他选项包括它们所在的服务器以及数据库参数是什么。如果它们在不同的服务器上,那么相对的“功率”、磁盘速度、I/O 和其他选项的无穷无尽的列表很容易造成差异。如果数据库参数不同,那么您将遇到同样的问题。

数据库调优既是一门艺术,也是一门科学。Oracle 有一整本书,还有很多其他资源。

于 2012-10-31T08:46:23.323 回答
1

“我们错过了什么吗?”

几乎可以肯定,但我们很难告诉你是什么。

CBO 从 9i 到 10g 有一些性能改进,但不太可能有那么大的不同。所以它一定是你的系统有一些变化,这显然是我们最难以诊断的事情,因为我们是盲目的和远程的。

所以,首先要排除的是一般系统差异——磁盘速度、I/O 瓶颈、内存大小等。你说你有两台服务器,它们有不同的规格吗?虽然调查这些事情需要系统管理员类型的帮助,但我们可以用一个问题打折扣:只是这个查询,还是你能用许多不同的查询重现这种效果?

如果只是查询,至少有三种可能的解释。

一是数据分布。两个数据库中的数据是如何填充的?如果 10g 是从 9i 数据库中导出的,它是否以某种方式排序?即使 ETL 过程不可能压缩和组织数据并以改善访问时间的方式构建新索引。

另一个是统计数据。10g 的统计数据是否新鲜且真实,而 9i 的统计数据是否陈旧且具有误导性?

第三种可能性是存储的执行计划。(您发布了一个带有文字的查询,这只适用于带有绑定变量的查询。)众所周知,日期范围的搜索很难调整。日期范围to_date('30/10/2012', 'dd/mm/yyyy') AND to_date('31/10/2012', 'dd/mm/yyyy')适合一种计划,而日期范围to_date('01/01/2010', 'dd/mm/yyyy') AND to_date('31/10/2012', 'dd/mm/yyyy') 可能很适合不同的方法。如果 9i 数据库上的现有计划适合更广泛的范围,那么对狭窄范围的查询可能需要很长时间。


当我一直在打字时,您已经发布了解释计划。杀手级细节在 9i 计划的底部:

Note: rule-based optimization

您没有任何表或索引的统计信息,因此优化器正在应用 RBO 的哑默认值。你真的应该解决这个问题,但这不是一个简单的任务。您可能需要收集所有表格的统计信息。您可能需要更改 init.ora 文件中的 OPTIMIZER_MODE。您可能需要对数据库上的所有查询进行回归测试。所以,这不是你应该轻易做的事情。

同时,如果这个查询困扰着你,你需要用老式的方式来处理基于规则的优化器。 了解更多

于 2012-10-31T09:00:08.967 回答
1

几点观察:

  • 您的索引是 DESCENDING 索引。这是一个基于函数的索引,因此在 RULE 优化器下它不会像预期的那样工作。
  • 您的 9i 计划仅显示对 OLD_IND 的访问,您的 10g 计划(您切断了重要的谓词位)显示了范围扫描 + inlist 迭代器,因此根据 RED_PK,它可能在 MEAS_ASS_ID 上访问,这可能更具选择性。
  • 在索引方面,回答您的查询,WHERE OLD_IND = 0 AND MEAS_ASS_ID IN (5022, 5003) AND read_date BETWEENOLD_IND equality, MEAS_ASS_ID equality and read_date range scanned, a better index is (OLD_IND , MEAS_ASS_ID , READ_DATE):最后进行范围扫描以减少 IO。
于 2012-10-31T12:13:41.483 回答
0

您是否尝试过对两台服务器上的查询运行解释,9i 的查询优化器与 10g 的查询优化器不同。10g 查询优化器更快且并行化。查看以下链接升级查询优化器

explain SELECT * FROM t_reading WHERE OLD_IND = 0 AND MEAS_ASS_ID IN (5022, 5003) AND read_date BETWEEN to_date('30/10/2012', 'dd/mm/yyyy') AND to_date('31/10/2012', 'dd/mm/yyyy');
于 2012-10-31T08:42:07.520 回答