use*_*116 5 oracle oracle-11g-r2 oracle-11g partitioning
我们有一个大型 Oracle 11gR2 实例,其中一些表最近在删除数据时变得很烦人。该数据库为大型优化集群提供动力,该集群从数据库获取输入元数据并存储文件(使用 11g 的 SecureFiles)和用于可视化的 1D-4D 输出数据。从数据库读取/写入非常快,在我们需要清理数据之前,一切都很好。
软件工程师被允许免费运行(阅读:我)并在没有任何分区的情况下设置这个系统,天真地假设删除会正常工作。我们的表结构如下,以前依赖于ON DELETE CASCADE
删除每个Case
where 的数据DeleteFlag = 1
。
/* Metadata tables */
Case(CaseId, DeleteFlag, ...) On Delete Cascade CaseId
OptimizationRun(OptId, CaseId, ...) On Delete Cascade OptId
OptimizationStep(StepId, OptId, ...) On Delete Cascade StepId
/* Data tables */
Files(FileId, CaseId, Blob) /* deletes are near instantateous here */
/* Data per run */
OnedDataX(OptId, ...)
TwoDDataY1(OptId, ...) /* packed representation of a 1D slice */
/* Data not only per run, but per step */
TwoDDataY2(StepId, ...) /* packed representation of a 1D slice */
ThreeDDataZ(StepId, ...) /* packed representation of a 2D slice */
FourDDataZ(StepId, ...) /* packed representation of a 3D slice */
/* ... About 10 or so of these tables exist */
Run Code Online (Sandbox Code Playgroud)
扇出看起来像:1 个案例 = 50 次运行 = 2000 步 = 数据表中的 5-35M 行。数据表的总和约为 500GB,仅差 1B 行。
在大姐姐网站上的一些帮助下,我得出了一个可能适用于我们的设置的分区方案(即分区方式CaseId
)。它使用 LIST-REFERENCE 复合分区,如下所示:
/* Metadata tables */
Case(CaseId, DeleteFlag, ...)
OptimizationRun(OptId, CaseId, ...)
Partition By List (CaseId)
( partition default_case values (default) )
/* Some PL/SQL is run when we add a Case to do:
* alter table OptimizationRun split partition ...
*/
OptimizationStep(StepId, OptId, ...)
Partition By Reference (Fk_OptId)
/* Data Tables */
OnedDataX(OptId, ...)
Partition By Reference (Fk_OptId)
...
FourDDataZ(StepId, ...) /* packed representation of a 3D slice */
Partition By Reference(Fk_StepId)
Run Code Online (Sandbox Code Playgroud)
设置起来很轻松,改进了我们通常的可疑查询的许多计划,并使我们能够删除单个DROP PARTITION
. 这就是我遇到问题的地方:索引重建!
当前执行删除操作的伪 PL/SQL 如下所示:
for casedel in (select CaseId from Case where DeleteFlag = 1)
loop
execute immediate 'alter table OptimizationRun'
|| ' drop partition case_' || casedel.CaseId
|| ' update indexes';
end loop;
delete from Case where DeleteFlag = 1;
commit;
Run Code Online (Sandbox Code Playgroud)
我们最终会发现数据表上的某些索引与 REFERENCE 分区中使用的外键无关。
我真的必须为ALTER INDEX blah REBUILD
这些辅助索引中的每一个创建状态,还是有更聪明的方法?
更新:一些实际的 DDL,为您带来阅读乐趣。
create table opt_case (
case_id number not null,
name varchar2(240) not null,
delete_date date,
constraint pk_optcase primary key (case_id) using index
);
create table opt_run (
opt_run_id number not null,
case_id number not null,
constraint pk_opt_run primary key (opt_run_id) using index,
constraint fk_opt_run_case
foreign key (case_id) references opt_case (case_id)
)
partition by list (case_id)
(
-- This is the catch-all partition. It is an error to insert into
-- this partition; it will be unused. Instead this is the
-- partition which is split when a new CASE_ID is added to
-- OPTCASE.
partition default_case values (default)
);
create index idx_fk_opt_run_case on opt_run (case_id);
create table opt_step (
opt_step_id number not null,
opt_run_id number not null,
step number not null,
step_value number(7,2),
constraint pk_opt_step primary key (opt_step_id) using index enable,
constraint fk_opt_step_opt_run
foreign key (opt_run_id) references opt_run (opt_run_id)
)
-- This is the golden ticket from here on out for partitioning.
-- Attach to the foreign key on OPT_RUN_ID to enjoy the
-- parent table partitioning on CASE_ID.
partition by reference (fk_opt_step_opt_run);
create index idx_fk_opt_step_opt_run on opt_step (opt_run_id);
-- One of the bigger data tables for reference
create table twod_data (
opt_step_id number not null,
spatial_coord_id number not null,
in_group number(1,0),
z_value number(3,0),
y_value number(5,3),
x_value number(5,1),
constraint pk_twod_data primary key (opt_step_id, spatial_coord_id),
constraint fk_twod_data_spat_coord
foreign key (spatial_coord_id)
references twod_spatial_cord (spatial_coord_id),
constraint fk_2d_data_opt_step
foreign key (opt_step_id) references opt_step (opt_step_id)
)
partition by reference (fk_2d_data_opt_step);
create index idx_fk_2d_data_opt_step on twod_data (opt_step_id);
Run Code Online (Sandbox Code Playgroud)
像这样的索引idx_fk_2d_data_opt_step
最终需要在DROP PARTITION
子句之后重建。
插入数据表是无趣的,简单的INSERT INTO blah
。在Case
创建过程现在看起来像:
-- Add the CASE
insert into opt_case (name) values (p_CaseName) returning case_id into v_CaseId;
commit;
-- Add partition for the CASE
execute immediate 'alter table opt_run'
|| ' split partition default_case values (' || v_CaseId || ')'
|| ' into (partition case_' || v_CaseId ||', partition default_case)';
-- Because we split an empty partition, no index rebuild required
Run Code Online (Sandbox Code Playgroud)