如何在插入

时间:2017-03-17 22:00:56

标签: oracle oracle12c

我有一个包含两个索引的表。我一次运行一个插件,每1000行提交一次。我无法进行批量插入,因为业务逻辑需要逐行检查更新的数据。

我的索引导致非常高的db_file_sequential_read等待。我可以命令传入的数据在这个索引上避免这些,但是我在不同的索引上遭受同样的惩罚。

实际的表太长而无法禁用并随后重新创建索引。

这显示了我所遭受的缓慢。第一组数字来自使用加密表空间的登台服务器。第二组数字来自使用非加密表空间的生产服务器。

-- create random test data in foo
create table foo as (
  select dbms_random.random() id, dbms_random.string('U', 25) val 
  from dual connect by level <= 100000
);
create index foo_id_idx on foo (id, val);

-- create data table in bar
create table bar as (
  select * from foo where 0 = 1
);

-- populate bar with unordered data (3.12s / 1.22s)
insert into bar select * from foo; commit;

-- add id index
create index bar_id_idx on bar (id);

-- populate indexed bar with unordered data (36.73s / 2.24s)
truncate table bar;
insert into bar select * from foo; commit;

-- populate indexed bar with id ordered data (4.84s / 0.6s)
truncate table bar;
insert into bar select * from foo order by id; commit;

-- add val index (actual production setup)
create index bar_val_idx on bar (val);

-- populate multi-indexed bar with unordered data (84.482s / 3.1s)
truncate table bar;
insert into bar select * from foo order by val; commit;

-- populate multi-indexed bar with id ordered data (50.641s / 2.631s)
truncate table bar;
insert into bar select * from foo order by id; commit;

-- alter index on foo to support order by clause
drop index foo_id_idx;
create index foo_val_idx on foo (val, id);

-- populate multi-indexed bar with val ordered data (37.31s / 2.66s)
truncate table bar;
insert into bar select * from foo order by val; commit;

这似乎是第二个指数从5s到84s的巨大惩罚。当然,我可以通过排序数据来绕过一个索引的大部分惩罚,但两者都不能。我应该查看缓冲区,缓存,内存或其他东西以帮助避免磁盘IO,还是应该查看其他一些策略,如索引组织表?

编辑1:从生产箱中添加数字&amp;等待信息。

在使用实际插入过程进行生产的一小时内(不是上面的简化示例): 处决56,715 行处理56,715 解析1 磁盘读取36,958 排序0 缓冲区获得754,970 db_file_sequential_read等待323s 内存/ CPU等待26s

2 个答案:

答案 0 :(得分:0)

如果您存储两份副本,则可能会以两个不同的顺序存储相同的数据:

  • 物化视图
  • 由IOT支持(val,id)密钥
  • 刷新提交
  • 启用高级查询重写,以使mview索引可用于对原始表的查询

这可以批量更新,从而为自己的维护提供一些利润。保持手指交叉,以便高级查询重写正常工作。

答案 1 :(得分:0)

mview的可执行示例。 如果且仅当第二个索引的逐行插入成为问题时,由于在提交时批量更新mview,这很难执行得更快。

set timing on

create table foo (
    id number,
    val varchar2(30)
) pctfree 0;

create index foo_id_idx on foo (id, val);

alter table foo
    add constraint pk_foo primary key (id) using index foo_id_idx;

create materialized view log on foo with primary key;

create table mv_foo (
    id number,
    val varchar2(30),
    constraint pk_mv_foo primary key (val, id)
) organization index;

create materialized view mv_foo
on prebuilt table
refresh fast on commit with primary key
enable query rewrite
as
select id, val
from foo;

begin
  -- to reset mview staleness
  dbms_mview.refresh('mv_foo', method => 'c');
end;
/

insert into foo(id, val)
select dbms_random.random(), dbms_random.string('U', 25)
  from dual connect by level <= 10000;
commit;

begin
  dbms_stats.gather_table_stats(user, 'foo');
  dbms_stats.gather_table_stats(user, 'mv_foo');
end;
/

explain plan for
select /*+ first rows */
  id, val
from foo
order by id, val;

select * from table(dbms_xplan.display);

explain plan for
select /*+ first rows */
  id, val
from foo
order by val, id;

select * from table(dbms_xplan.display);

请参阅第二个声明中按VAL过滤FOO时透明使用mview IOT:

explain plan for select * from foo where id = :x

explain plan succeeded.
6ms elapsed
select * from table(dbms_xplan.display)

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------
Plan hash value: 2466643623

-------------------------------------------------------------------------------
| Id  | Operation        | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |            |     1 |    33 |     2   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| FOO_ID_IDX |     1 |    33 |     2   (0)| 00:00:01 |
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("ID"=TO_NUMBER(:Z))


explain plan for select * from foo where val = :x

explain plan succeeded.
25ms elapsed
select * from table(dbms_xplan.display)

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------
Plan hash value: 386525678

------------------------------------------------------------------------------
| Id  | Operation        | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |           |     1 |    33 |     2   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| PK_MV_FOO |     1 |    33 |     2   (0)| 00:00:01 |
------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("MV_FOO"."VAL"=:X)

您需要QUERY REWRITE系统权限才能正常工作。