我有一个包含 3000K 行的表“MSATTRIBUTE”。我使用以下查询来检索数据,该查询具有不同的执行计划,具有相同的数据库数据但在不同的环境中。在一个环境中,它显示为全表扫描,因此查询非常慢,但在另一个环境中,它都使用索引扫描,这非常好,每个人都知道为什么它在一个环境中进行全表扫描,因为我为他们建立了索引,我该怎么做就像我在 env 1 中测试的一样,让我们成为索引扫描。如何改进这个查询?
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 的情况,除了
- 执行计划必须执行 INDEX SKIP SCAN,因为 REDLINE_MSATTRIBUTE_INDEX1 在两列之间具有 CHANGE_ID
- 无论如何,数据库必须转到表中才能获取 CLASS 和 CHANGE_RELEASE_DATE。
因此,您可以通过在(CHANGE_RELEASE_DATE, CLASS, OBJECT_ID, ATTID)
. 但正如我前面所说,在不了解您的情况的情况下,这些只是不明智的猜测。
如果两个表中的行顺序不同,则两个系统中的索引可能具有不同的聚类因子,因此估计索引访问的成本不同。检查表和索引的统计信息,包括聚类因子,看看是否有显着差异。
另外,这两个系统的解释计划中是否提到了动态抽样?
当 oracle 有索引并决定使用/不使用它时,可能是因为 1)您可能对 OPTIMIZER_MODE 有不同的设置 - 确保它不在 RBO 上。2) 数据不同 - 在这种情况下,oracle 可能会以不同方式评估查询统计信息。3)数据相同,但统计数据不是最新的。在这种情况下 - 收集统计数据
dbms_stats.gather_table_stats('your3000Ktable',cascade=>true);
4)oracle不会在一个环境中使用索引的原因还有很多,我建议比较参数(例如OPTIMIZER_INDEX_COST_ADJ等...)
一个直接的问题是这块 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;