2017-03-17 99 views
0

我有一個包含兩個索引的表。我每次運行一個插入,每1000行提交一次。我無法進行批量插入,因爲業務邏輯需要逐行檢查更新的數據。如何在插入期間避免索引上的db_file_sequential_read

我的索引造成非常高的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; 

對於第二個索引從5秒到84秒這似乎是一個巨大的懲罰。當然,我可以通過訂購數據來繞過一個索引的大部分處罰,但不能同時處理兩者。我是否應該查看緩衝區,緩存,內存或其他內容以幫助避免磁盤IO,還是應該查看其他策略,如索引組織表?

編輯1:從生產箱中添加數字&等待信息。

在生產與實際的插入處理(不高於簡化例子)1小時: 處決56715個 行耗時56715名 解析1 磁盤讀取36958個 排序0 緩衝區獲取754970 db_file_sequential_read等待323S 存儲器/ CPU等待26S

+1

您正在運行的機器的規格是什麼?這些時間看起來非常緩慢。其他一些事情。一世。每行需要完成的處理是什麼?你確定*這不能作爲公牛插入的一部分嗎? II。你確定等待事件來自索引維護嗎? III。你的桌子的大小是多少,無論是在行和GB – BobC

+0

@Aaron,我同意BobC你的運行時間似乎很慢。我在臺式電腦上運行了整個腳本,所有時間都比我的速度慢了10倍以上。在擔心數據結構之前,您可能需要查看操作系統,硬件,SAN等。或者查看一些AWR數據以查看數據庫的性能,例如:select * from dba_hist_sysmetric_history 其中metric_name ='平均同步單塊讀取延遲';'。 –

+0

@BobC這是一個臨時服務器,其規格遠遠低於生產服務器,但配置完全相同,並且使用相同的NAS。我也意識到我正在爲表和索引使用加密的表空間。這就是說 - 我更關心這個例子中表現的相對差異。我將生產服務器中的數字添加到未加密的表空間中,直到原始問題。如果你仍然認爲表現不佳,那麼我會好奇進一步調查。 – Aaron

回答

0

你可能已經存儲在兩個不同的順序相同的數據,如果存儲兩個副本:

  • 物化視圖
  • 通過IOT支持與(VAL,ID)鍵
  • 刷新上對原始表提交
  • 先進的查詢重寫啓用,爲MVIEW指數爲可用通過查詢

這可能批量更新,從而獲得一定的利潤來償還自己的維護費用。保持你的手指交叉進行高級查詢重寫以正常工作。

+1

所以你建議兩組插入? IOT如何提供幫助? – BobC

+0

沒辦法:)物化視圖自動維護。 是的,您需要在表格上查看MATERIALIZED VIEW LOG –

+1

MV如何幫助插入性能? – BobC

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); 

請參閱如何MVIEW在第二語句時FOO過濾通過VAL 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重寫系統權限。