Sql 重建索引时资源正忙
有一个表Sql 重建索引时资源正忙,sql,oracle,oracle10g,indexing,locking,Sql,Oracle,Oracle10g,Indexing,Locking,有一个表T,列a: CREATE TABLE T { id_t integer not null, text varchar2(100), a integer } / ALTER TABLE T ADD CONSTRAINT PK_T PRIMARY KEY (ID_T) / 索引是这样创建的: CREATE INDEX IDX_T$A ON T(a); 还有这样一个检查约束: ALTER TABLE T ADD CONSTRAINT CHECK (a is null or
T
,列a
:
CREATE TABLE T {
id_t integer not null,
text varchar2(100),
a integer
}
/
ALTER TABLE T ADD CONSTRAINT PK_T PRIMARY KEY (ID_T)
/
索引是这样创建的:
CREATE INDEX IDX_T$A ON T(a);
还有这样一个检查约束:
ALTER TABLE T ADD CONSTRAINT CHECK (a is null or a = 1);
T
中的大多数记录都有空值a
,因此,如果索引处于一致状态且其统计信息是最新的,则使用索引的查询速度非常快
但是问题是一些行的a
的值变化非常频繁(一些行得到null值,一些行得到1),我需要重建索引,比如说每小时一次
但是,当作业执行此操作时,尝试重建索引时,通常会出现异常:
ORA-00054: resource busy and acquire with NOWAIT specified
有人能帮我解决这个问题吗?你有没有试过在索引重建语句中添加“ONLINE”
编辑:如果联机重建不可用,则可以查看提交实体化视图上的快速刷新,以存储列a为1的行的rowid或主键
首先看一下文档:-
您将在表上创建一个实体化视图日志,然后创建一个实体化视图
请特别考虑这方面的资源需求:对主表的更改需要将更改向量写入Materialized view log,这实际上是每个更改的附加插入。然后,必须使用其他查询将更改传播到另一个表(已实现的视图存储表)。这绝不是一个低影响的选项。由于所讨论的字段的基数非常低,我建议使用位图索引并完全跳过重建
CREATE BITMAP INDEX IDX_T$A ON T(a);
注意(如注释中所述):位图索引的事务性能非常低,因此只有在很少重叠事务对表进行更新的情况下,这种方法才能很好地工作 大多数情况下不需要重建索引。当然,新创建的索引是有效的,它们的效率会随着时间的推移而降低。但这一过程在一段时间后停止——它只是收敛到某种程度 如果您确实需要优化索引,请尝试使用侵入性较小的DDL命令“ALTERINDEX SHRINK SPACE COMPACT”
PS:我还建议您为表空间存储使用一些较小的块大小(4K或8K) 重建性能 大多数Oracle专家对频繁重建索引表示怀疑。例如,快速浏览一下演示文稿,就会发现索引的行为并不像许多人想象的那样幼稚 该演示文稿中的一个相关要点是“完全删除的块被回收,通常不会有问题”。如果您的值完全改变,那么您的索引不应该无限大。虽然索引的使用方式不典型,但是 行为可能是一件好事 这里有一个简单的例子。创建100万行并索引其中的100行
--Create table, constraints, and index.
CREATE TABLE T
(
id_t integer primary key,
text varchar2(100),
a integer check (a is null or a = 1)
);
CREATE INDEX IDX_T$A ON T(a);
--Insert 1M rows, with 100 "1"s.
insert into t
select level, level, case when mod(level, 10000) = 0 then 1 else null end
from dual connect by level <= 1000000;
commit;
--Initial sizes:
select segment_name, bytes/1024/1024 MB
from dba_segments
where segment_name in ('T', 'IDX_T$A');
SEGMENT_NAME MB
T 19
IDX_T$A 0.0625
重建统计数据
担心数据变化如此剧烈的对象的统计数据是件好事。但同样,尽管您的系统与众不同,但它可以与默认的Oracle行为配合使用。虽然索引的行可能会完全改变,但相关的统计数据可能保持不变。如果始终有100行索引,则行数、块数和区分度将保持不变
--The the index size is the same.
select segment_name, bytes/1024/1024 MB
from dba_segments
where segment_name in ('T', 'IDX_T$A');
SEGMENT_NAME MB
T 19
IDX_T$A 0.0625
如果100行从完全随机变为彼此非常接近,那么聚类因子可能会发生显著变化。但即使这样也可能无关紧要。如果有数百万行,但只有100行被索引,那么不管聚类因子如何,优化器的决策可能都是相同的。读取1个块(可怕的聚类因子)或读取100个块(最坏的聚类因子)看起来仍然比对数百万行进行全表扫描要好得多
但统计数据是复杂的,我肯定过于简化了。如果需要以特定的方式保存统计数据,则可能需要锁定它们。不幸的是,不能只锁定索引,但可以锁定表及其依赖索引
begin
dbms_stats.lock_table_stats(ownname => user, tabname => 'T');
end;
/
无论如何都要重建
如果仍然需要重建,@Robe Eleckers重试的想法应该会奏效。虽然它不是一个异常,但更容易设置
会话仍然需要获得表上的独占锁,但这将使找到正确的机会窗口变得更加容易。您可以通过重试机制来处理它。捕获资源繁忙异常并重试,直到成功。快速更改对索引有什么影响,导致需要频繁重建?有关它的统计信息很快过期。重新编译regathers统计信息并使索引更小(读取对它的查询会更快)。联机重建是我无法使用的企业选项。您能否提供一个示例,说明Materialized视图的含义?它看起来真的很不错。如果多个会话中的值变化很快,那么这对并发性来说就相当糟糕了,尽管如此。如果数据通过多个进程同时更改且非常频繁,则可以使用位图索引。顺便说一句,
select*from v$option,其中parameter='Bit-mapped index'
表示它在standart edition中也不可用。想象一下,当表中有数百万行,而只有一百行时的情况没有索引列的not null值,一小时后not null值有绝对不同的行(以前的行中有null),您确定索引不会继续永久增长并变得越来越低效率吗?Oracle索引正在进行自我碎片整理。至少在某种程度上。它还取决于列索引的顺序。如果某个索引不适合您的搜索需求,请查找“星型设计模式”——它用于数据仓库系统。这很简单。或者还有一个选项“压缩”索引。还有一个注释,索引“大小”可以表达给我们
begin
dbms_stats.lock_table_stats(ownname => user, tabname => 'T');
end;
/
alter session set ddl_lock_timeout = 500;