5

我有一个包含 3000K 行的表“MSATTRIBUTE”。我使用以下查询来检索数据,该查询具有不同的执行计划,具有相同的数据库数据但在不同的环境中。在一个环境中,它显示为全表扫描,因此查询非常慢,但在另一个环境中,它都使用索引扫描,这非常好,每个人都知道为什么它在一个环境中进行全表扫描,因为我为他们建立了索引,我该怎么做就像我在 env 1 中测试的一样,让我们​​成为索引扫描。如何改进这个查询?

4

4 回答 4

4

如果不了解您的数据模型和您的业务,就很难给出具体的积极建议。但这里有一些关于您的索引策略的注释,以及为什么我猜优化器没有使用您拥有的索引。

在子查询中,REDLINE_MSATTRIBUTE 的访问路径来自三列:

  • 班级
  • OBJECT_ID
  • CHANGE_RELEASE_DATE。

CLASS 未编入索引。但这大概不是很有选择性。OBJECT_ID 是复合索引的前导列,但其他列与子查询无关。

但最大的问题是 CHANGE_RELEASE_DATE。这根本没有索引。这是个坏消息,因为您的一个主键查找会产生一个日期,然后将其与 CHANGE_RELEASE_DATE 进行比较。如果一列没有被索引,那么数据库必须读取表来获取它的值。

主要查询驱动

  • ATTID
  • CHANGE_ID
  • OBJECT_ID(再次)
  • CHANGE_RELEASE_DATE(再次)
  • 类(再次)
  • OLD_VALUE

ATTID 已编入索引,但该索引的选择性如何?优化器可能不认为它很有选择性。ATTID 也在一个带有 CHANGE_ID 和 OLD_VALUE 的复合索引中,但它们都不是前导列,所以这不是很有用。我们已经讨论过 CLASS、CHANGE_RELEASE_DATE 和 OBJECT_ID。

如果索引比表扫描便宜(读取次数更少),优化器只会选择使用索引。这通常意味着 WHERE 子句条件需要映射到索引的前导(即最左边)列。这可能是子查询中的 OBJECT_ID 和 ATTID 的情况,除了

  1. 执行计划必须执行 INDEX SKIP SCAN,因为 REDLINE_MSATTRIBUTE_INDEX1 在两列之间具有 CHANGE_ID
  2. 无论如何,数据库必须转到表中才能获取 CLASS 和 CHANGE_RELEASE_DATE。

因此,您可以通过在(CHANGE_RELEASE_DATE, CLASS, OBJECT_ID, ATTID). 但正如我前面所说,在不了解您的情况的情况下,这些只是不明智的猜测。

于 2013-01-23T17:35:33.540 回答
3

如果两个表中的行顺序不同,则两个系统中的索引可能具有不同的聚类因子,因此估计索引访问的成本不同。检查表和索引的统计信息,包括聚类因子,看看是否有显着差异。

另外,这两个系统的解释计划中是否提到了动态抽样?

于 2013-01-23T17:04:52.587 回答
1

当 oracle 有索引并决定使用/不使用它时,可能是因为 1)您可能对 OPTIMIZER_MODE 有不同的设置 - 确保它不在 RBO 上。2) 数据不同 - 在这种情况下,oracle 可能会以不同方式评估查询统计信息。3)数据相同,但统计数据不是最新的。在这种情况下 - 收集统计数据

dbms_stats.gather_table_stats('your3000Ktable',cascade=>true);

4)oracle不会在一个环境中使用索引的原因还有很多,我建议比较参数(例如OPTIMIZER_INDEX_COST_ADJ等...)

于 2013-02-10T08:41:19.487 回答
0

一个直接的问题是这块 SELECT RELEASE_DATE FROM CHANGE WHERE ID = 136972355 (这段代码将为返回的每一行运行,它不需要......更好的方法是使用单个笛卡尔表,所以它只运行一次并返回一个静态值进行比较....

示例 1:

Select * From Table1, (Select Sysdate As Compare From Dual) Table2 Where Table1.Date > Table2.Compare.

总是比 Select * from Table1 Where Date > Sysdate -- Sysdate 将被每行调用,因为它是基于动态函数的值。前面的示例将解析一次文字并大大加快速度。我相信这绝对是一次伤害您的查询并强制进行表扫描的部分。

我也相信这是执行查询的更有效方式。

Select  
            REDLINE_MSATTRIBUTE.ATTID
           ,REDLINE_MSATTRIBUTE.VALUE
  From 
            REDLINE_MSATTRIBUTE
           ,(
                SELECT  ATTID
                        ,CHANGE_ID
                        ,MIN(CHANGE_RELEASE_DATE) RELEASE_DATE
                 FROM   REDLINE_MSATTRIBUTE
                       ,(SELECT RELEASE_DATE FROM CHANGE WHERE ID = 136972355) T_COMPARE                
                WHERE   CLASS             = 9000
                  And   OBJECT_ID           = 32718015
                  And   CHANGE_RELEASE_DATE > T_COMPARE.RELEASE_DATE
                  And   ATTID IN (1564, 1565)
                GROUP 
                   BY   ATTID,
                        CHANGE_ID
            ) T_DYNAMIC
Where         
        REDLINE_MSATTRIBUTE.ATTID = T_DYNAMIC.ATTID   
    And REDLINE_MSATTRIBUTE.CHANGE_ID = T_DYNAMIC.CHANGE_ID
    And REDLINE_MSATTRIBUTE.RELEASE_DATE = T_DYNAMIC.RELEASE_DATE
    And CLASS     = 9000
    And OBJECT_ID = 32718015
    And OLD_VALUE ='Y'
Order 
   By   REDLINE_MSATTRIBUTE.ATTID,
        REDLINE_MSATTRIBUTE.VALUE;  
于 2013-01-23T18:00:49.783 回答