优化IN子句

bja*_*jan 3 sql oracle query-optimization oracle10g sql-optimization

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

select * from Entries 
where RefKey in (select RefKey 
                 from Entries 
                 where KeyStat = 1) 
and RefKey = Key;
Run Code Online (Sandbox Code Playgroud)

这里RefKey,Key和KeyStat都被编入索引.该表在另一列上分区,此列未在此处使用.在此查询中,我选择当前活动的主密钥(如果RefKey =密钥然后是主密钥)(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 |       |       |
----------------------------------------------------------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

我担心ID = 3"表格访问已满".如果此查询中使用的所有列都已编制索引,那么为什么oracle正在执行全表扫描.

如何优化?如果我在内部查询中放入一些值,它返回的速度要快得多.


解释为什么子查询是必要的:我选择具有至少一个活动密钥的整批.Refkey不是唯一的; 例如:

Key=1, RefKey=1, Stat=1 
Key=2, RefKey=1, Stat=0
Key=3, RefKey=2, Stat=1
Run Code Online (Sandbox Code Playgroud)

APC*_*APC 5

"我担心ID = 3"表访问已满".如果此查询中使用的所有列都已编入索引,那么为什么oracle正在进行全表扫描."

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

通过过滤子查询获得的速度提高来验证此猜测.

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


"将有数百万条KeyStat = 0的条目,1000条中只有少数会有1条所以使用索引将是有益的."

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

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