我有一个大表,我需要删除数百万行。这需要很长时间,因此我通过 CTAS 创建了一个新记录,其中没有我想要删除的记录。在这个表上,我创建了与原始表相同的索引和外键,然后删除了原始表。我重新计算了统计数据。一切都完成得很快而且没有任何问题。然而,现在使用表格的速度出奇地慢。尽管执行计划相同,但对主键上的记录进行 FORALL 删除需要更长的时间(仍然是索引快速全扫描)。该怎么办?
CTAS 减慢表速度的两种常见方式是缺少压缩等关键表属性,或者以不同的顺序加载表,从而降低索引性能。
您确定完美地重新创建了新表格吗?也许您忘记了一个重要的表属性,例如压缩。下面的示例演示了压缩等属性如何不会自动复制到新表中:
-- Create a compressed table.
create table compressed compress as
select 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' columnA
from dual
connect by level <= 100000;
-- CTAS but forgot the COMPRESS keyword.
create table uncompressed /* forgot compress! */ as
select * from compressed;
-- The uncompressed table is 3 times larger, which may slow down future DML.
select segment_name, bytes
from dba_segments
where segment_name in ('COMPRESSED', 'UNCOMPRESSED')
order by 1;
SEGMENT_NAME BYTES
------------ -------
COMPRESSED 2097152
UNCOMPRESSED 6291456
您可以使用类似
SELECT * FROM DBA_TABLES
的查询检查表属性,也可以使用类似 select dbms_metadata.get_ddl('TABLE', 'TABLE_NAME') from dual;
的查询获取整个表 DDL
即使数据结构和数据相同,数据物理加载的“顺序”也会对性能产生影响。例如,当相关列按顺序插入时,索引可以更有效地从表中读取数据。发生这种情况是因为每个索引条目都包含一个指向表中数据块的指针,该数据块通常为 8KB。由于索引通常按顺序读取,因此如果有序值彼此相邻存储,效率会更高。如果表值完全无序,您最终可能会遇到这样的情况:从索引中读取 1% 的值需要从表中拉取 100% 的块。
--Create a well-ordered table and index.
create table ordered_data as
select level columnA
from dual
connect by level <= 100000
order by level;
create index ordered_data_idx on ordered_data(columnA);
--Create a randomly ordered table and index.
create table unordered_data as
select level columnA
from dual
connect by level <= 100000
order by dbms_random.value;
create index unordered_data_idx on unordered_data(columnA);
聚类因子是衡量索引效率的指标,与数据的有序程度有关。下面的查询显示排序数据可以产生巨大的影响。
select index_name, clustering_factor
from dba_indexes
where index_name in ('ORDERED_DATA_IDX', 'UNORDERED_DATA_IDX');
INDEX_NAME CLUSTERING_FACTOR
------------------ -----------------
ORDERED_DATA_IDX 153
UNORDERED_DATA_IDX 99357
修复
alter table uncompressed compress;
alter table uncompressed move;
对于排序数据,有一些高级功能,例如聚类,但重做 CTAS 并在必要时添加
ORDER BY
子句可能会更简单。