为什么oracle表已索引但还是全表扫描?

问题描述 投票:0回答:5

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

database performance oracle oracle11g query-optimization
5个回答
4
投票

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

在子查询中,REDLINE_MSATTRIBUTE 的访问路径由三列驱动:

  • 课程
  • OBJECT_ID
  • CHANGE_RELEASE_DATE。

CLASS 未建立索引。 但这可能不是很有选择性。 对象ID 是复合索引的前导列,但其他列与子查询无关。

但最大的问题是CHANGE_RELEASE_DATE。 这根本没有索引。 这是个坏消息,因为您的一个主键查找会生成一个日期,然后将其与 CHANGE_RELEASE_DATE 进行比较。 如果某列未建立索引,则数据库必须读取该表才能获取其值。

主要查询开车出发

  • 态度
  • CHANGE_ID
  • OBJECT_ID(再次)
  • CHANGE_RELEASE_DATE(再次)
  • 课堂(再次)
  • 旧值

ATTID 已建立索引,但该索引的选择性如何? 优化器可能认为它不是很有选择性。 ATTID 也在具有 CHANGE_ID 和 OLD_VALUE 的复合索引中,但它们都不是前导列,因此这不是很有用。 我们已经讨论了 CLASS、CHANGE_RELEASE_DATE 和 OBJECT_ID。

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

  1. 执行计划必须执行 INDEX SKIP SCAN,因为 REDLINE_MSATTRIBUTE_INDEX1 在两列之间有 CHANGE_ID
  2. 数据库无论如何都必须访问表来获取 CLASS 和 CHANGE_RELEASE_DATE。

因此,通过在

(CHANGE_RELEASE_DATE, CLASS, OBJECT_ID, ATTID)
上建立索引可能会得到一些改进。 但正如我之前所说,在不了解您的情况的情况下,这些只是不明智的猜测。


3
投票

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

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


1
投票

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

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

4) Oracle 不在一种环境下使用索引的原因还有很多,我建议比较参数(例如 OPTIMIZER_ INDEX_COST_ADJ 等...)


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.

总是比 从表 1 中选择 *,其中日期 > 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;  

0
投票

Oracle 优化器并不总是正确选择最佳访问路径。

但是,有时候它比我们聪明。

如果您有一个可以在几个块中读取的表,那么全表扫描 (FTS) 比读取索引然后从数据块中的索引中定位数据,对每条记录重复此操作的 I/O 效率更高。

如果索引可以更好地利用 I/O,请查看 Oracle“提示”。 这将帮助您创建“索引”提示。

另一个问题是“绑定偷看”。 本评论无法涵盖这一点,因此需要您进行研究以及如何收集数据的“直方图”。

© www.soinside.com 2019 - 2024. All rights reserved.