3

我正在使用 Oracle 10g。这是我的查询

select * from Entries 
where RefKey in (select RefKey 
                 from Entries 
                 where KeyStat = 1) 
and RefKey = Key;

这里 RefKey、Key 和 KeyStat 都被索引了。该表在此处未使用的另一列上进行了分区。在此查询中,我选择当前活动的主密钥(如果 RefKey = Key 然后是主密钥)(KeyStat = 1)。下面是使用 SQLTools 1.21 RC3 执行此查询的计划。

----------------------------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name           | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |                |     1 |   270 |   218K  (1)| 00:43:37 |       |       |
|   1 |  NESTED LOOPS SEMI                  |                |     1 |   270 |   218K  (1)| 00:43:37 |       |       |
|   2 |   PARTITION RANGE ALL               |                |     1 |   262 |   218K  (1)| 00:43:37 |     1 |    12 |
|*  3 |    TABLE ACCESS FULL                | ENTRIES        |     1 |   262 |   218K  (1)| 00:43:37 |     1 |    12 |
|*  4 |   TABLE ACCESS BY GLOBAL INDEX ROWID| ENTRIES        |    10M|    77M|     3   (0)| 00:00:01 | ROWID | ROWID |
|*  5 |    INDEX RANGE SCAN                 | IND_ENTR_REFKEY|     1 |       |     2   (0)| 00:00:01 |       |       |
----------------------------------------------------------------------------------------------------------------------

我担心 ID = 3 "TABLE ACCESS FULL"。如果此查询中使用的所有列都已编入索引,那么为什么 oracle 会进行全表扫描。

如何优化?如果我在内部查询中放入一些值,它会返回得更快。


解释为什么需要子查询:我选择具有至少一个活动键的整个批次。Refkey 不是唯一的;例如:

Key=1, RefKey=1, Stat=1 
Key=2, RefKey=1, Stat=0
Key=3, RefKey=2, Stat=1
4

3 回答 3

5

“我担心 ID = 3 "TABLE ACCESS FULL"。如果此查询中使用的所有列都已编入索引,那么为什么 oracle 会进行全表扫描。”

优化器忽略 KEYSTAT 上的索引。我猜这是因为 KEYSTAT 不是很有选择性(相对较少的不同值)和/或因为这些值均匀分布在 ENTRIES 表的整个范围内。如果查询几乎要命中表中的每个块,则 FULL TABLE SCAN 是最佳路径。

通过过滤子查询可以提高速度,从而验证了这个猜测。

正如其他人所建议的那样,重构您的语句以删除子查询将是提高性能的最佳方法。


“会有数百万个 KeyStat= 0 的条目,只有千分之几会有 1,因此使用索引将是有益的。”

偏斜的数据分布通常是性能问题的根源。你看,问题是,数据库不知道KEYSTAT=1 比 KEYSTAT=0 更具选择性。除非我们告诉它,这就是为什么您在收集有关该索引的统计信息时可能要考虑创建直方图的原因。 了解更多

请注意,直方图可能会导致问题并解决问题,尤其是对于使用绑定变量而不是文字的查询。因此,在将它们投入生产之前,先在沙坑中进行基准测试。

于 2011-07-26T07:52:29.403 回答
4

也许我错过了一些东西,但这不应该产生相同的结果吗?

select *
from Entries e
where e.KeyStat = 1 
  and e.RefKey = e.Key
于 2011-07-26T07:38:58.000 回答
1

你能做一个

EXPLAIN PLAN FOR select * from Entries 
where RefKey in (select RefKey 
                 from Entries 
                 where KeyStat = 1) 
and RefKey = Key;

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

你应该得到一个解释计划,最后有一堆额外的信息。具体来说,您对该操作 3 感兴趣。它不仅进行全表扫描,而且仅给出行/基数 1。实际上这意味着它认为它不会找到任何东西(因为它永远不会那里给出一个零值)。

您可以看出它不希望找到一行,因为尽管操作 4 涉及 1000 万行,但它给出的成本是“3”,而“2”是索引成本。它不期望从“3”开始的扫描找到任何东西,因此它从不期望将一个值插入索引扫描,因此它永远不会看到 10M 行。

所以我看到了两个问题。首先,它不使用 KeyStat 上的索引。其次,它低估了匹配返回的行数。第一个可能是由数据类型不匹配引起的。也许 KeyStat 是一个字符值。也许它不是索引中的前导列。也许索引已被禁用(在 ETL 作业期间?)。

奇怪的估计也是暗示性的。如果该列是索引中的前导列,我希望统计数据已经计算出该列的 max_val 为 1。如果它认为 max_val 为零,那将解释“你不会找到任何东西”估计,但它也没有用于快速找到 max_val 的索引。

于 2011-07-26T10:04:03.727 回答