我尝试使用ALTER TABLE MOVE...INCLUDING ROWS
作为faster alternative到DELETE
,但在以下情况下无法正常工作:
1.存在索引,并且
1.筛选条件导致空表
下面是一个例子:
create table t (
c1 int not null
);
create index t_index on t(c1);
insert into t values ( 1 );
insert into t values ( 2 );
alter table t move including rows where c1 > 2 update indexes;
字符串
这将导致一个空表,但:
select * from t;
型
| C1 |
| ------------ |
| 1 |
| 2 |
这是B/c,它使用t_index
,如查询计划所示:
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 13 | 1 (0)| 00:00:01 |
| 1 | INDEX FULL SCAN | T_INDEX | 1 | 13 | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------
型
如果我们不强制索引,我们会得到正确的结果:
select /*+no_index(t t_index)*/ *
from t;
---
(none)
型
如果过滤保留了一些行,我们不会得到这样的结果:
alter table t move including rows where c1 > 1 update indexes;
select * from t;
型
| C1 |
| ------------ |
| 2 |
Oracle数据库19 c企业版19.0.0.0.0 -生产。这是一个已知的bug,还是我误解了Oracle应该如何工作?
1条答案
按热度按时间z31licg01#
是的,这是一个bug。我可以复制到19.18晚(我没有任何更近的)。请注意,当您有一个没有索引的附加列时会发生什么:
字符串
测试结果:
型
它使用了索引(因为我暗示它这样做,否则它不会这样做),并且因为它需要从索引中没有的表段中获取一列,它开始从索引中存储的
ROWID
计算表块地址,但是ROWID
引用了一个不存在的段(旧的pre-move表),所以抛出了这个错误。这证明在ALTER TABLE MOVE INCLUDING ROWS
匹配0行的情况下,Oracle绕过了索引维护,但0行也将索引标记为可用,因此您有一个 usable 索引,其中包含旧的无效ROWID
s。绝对是个bug您的测试显示了一个不同的答案,而不是当索引被 * 独占 * 使用时出错。因为您没有引用索引中没有的任何列,所以它实际上根本不会访问表(这就是为什么您不必提示它使用索引,它认为这是一个优势,并选择它作为最佳路径)。因此,您的查询从索引本身获得了所需的一切,但索引中的数据是坏的,因为它没有在应该重建的时候重建。它不会出错,因为它从不尝试使用
ROWID
,因为它不需要访问表段。但这只是同一个问题的另一个症状:指向不存在的段的未重建索引。显然,update indexes
不会发生。请在Oracle支持下对此创建SR,当结果根据优化器选择的执行路径发生变化时,这肯定是一个错误。如果你没有一个MOS帐户,让我知道,我会为你做的。一个快速的bug搜索没有找到任何明显的匹配,所以它可能是没有人报告过的东西。