使用散列集群后,我的查询运行得慢得多(数据库时间的6.82%到76%)。而且AWR报告说,无锁->多块读取对象是关键。
查询是
SELECT count(1) INTO result FROM (
SELECT s_w_id, s_i_id, s_quantity
FROM bmsql_stock
WHERE s_w_id = in_w_id AND s_quantity < in_threshold AND s_i_id IN (
SELECT ol_i_id
FROM bmsql_district
JOIN bmsql_order_line ON ol_w_id = d_w_id
AND ol_d_id = d_id
AND ol_o_id >= d_next_o_id - 20
AND ol_o_id < d_next_o_id
WHERE d_w_id = in_w_id AND d_id = in_d_id
)
);
表ddl是(请注意order_line表不是集群的)
create cluster bmsql_stock_cluster (
s_w_id integer,
s_i_id integer
)
single table
hashkeys 300000000
hash is ( (s_i_id-1) * 3000 + s_w_id-1 )
size 270
pctfree 0 initrans 2 maxtrans 2
storage (buffer_pool keep) parallel (degree 96);
create table bmsql_stock (
s_w_id integer not null,
s_i_id integer not null,
s_quantity integer,
s_ytd integer,
s_order_cnt integer,
s_remote_cnt integer,
s_data varchar(50),
s_dist_01 char(24),
s_dist_02 char(24),
s_dist_03 char(24),
s_dist_04 char(24),
s_dist_05 char(24),
s_dist_06 char(24),
s_dist_07 char(24),
s_dist_08 char(24),
s_dist_09 char(24),
s_dist_10 char(24)
)
cluster bmsql_stock_cluster(
s_w_id, s_i_id
);
create unique index bmsql_stock_pkey
on bmsql_stock (s_i_id, s_w_id)
parallel 32
pctfree 1 initrans 3
compute statistics;
create cluster bmsql_district_cluster (
d_id integer,
d_w_id integer
)
single table
hashkeys 30000
hash is ( (((d_w_id-1)*10)+d_id-1) )
size 3496
initrans 4
storage (buffer_pool default) parallel (degree 32);
create table bmsql_district (
d_id integer not null,
d_w_id integer not null,
d_ytd decimal(12,2),
d_tax decimal(4,4),
d_next_o_id integer,
d_name varchar(10),
d_street_1 varchar(20),
d_street_2 varchar(20),
d_city varchar(20),
d_state char(2),
d_zip char(9)
)
cluster bmsql_district_cluster(
d_id, d_w_id
);
create unique index bmsql_district_pkey
on bmsql_district (d_w_id, d_id)
pctfree 5 initrans 3
parallel 1
compute statistics;
create table bmsql_order_line (
ol_w_id integer not null,
ol_d_id integer not null,
ol_o_id integer sort,
ol_number integer sort,
ol_i_id integer not null,
ol_delivery_d timestamp,
ol_amount decimal(6,2),
ol_supply_w_id integer,
ol_quantity integer,
ol_dist_info char(24)
);
create unique index bmsql_order_line_pkey
on bmsql_order_line (ol_w_id, ol_d_id, ol_o_id, ol_number)
compute statistics;
最后,多块读取对象相关指标:
Latch Activity:
Latch Name Get Requests Pct Get Miss Avg Slps /Miss Wait Time (s) NoWait Requests
// before
multiblock read objects 42,906 0.24 0.00 0 0
// after
multiblock read objects 302,570,536 87.49 0.04 22385 0
Latch Sleep Breakdown:
Latch Name Get Requests Misses Sleeps Spin Gets
multiblock read objects 302,570,536 264,712,892 11,385,692 254,114,619
Latch Miss Source:
Latch Name Where NoWait Misses Sleeps Waiter Sleeps
multiblock read objects kcbzibmlt 0 5,886,699 5,927,472
multiblock read objects kcbzibmlt: normal mbr free 0 5,498,253 5,457,785
以及具有统计信息的执行计划:
Plan hash value: 485221244
--------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
--------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.11 | 1472 | | | |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.11 | 1472 | | | |
| 2 | NESTED LOOPS | | 1 | | 4 |00:00:00.11 | 1472 | | | |
| 3 | NESTED LOOPS | | 1 | 103 | 220 |00:00:00.10 | 1240 | | | |
| 4 | VIEW | VW_NSO_1 | 1 | 390 | 220 |00:00:00.10 | 578 | | | |
| 5 | HASH UNIQUE | | 1 | 1 | 220 |00:00:00.10 | 578 | 1397K| 1397K| 1342K (0)|
| 6 | MERGE JOIN | | 1 | 390 | 221 |00:00:00.10 | 578 | | | |
|* 7 | TABLE ACCESS HASH | BMSQL_DISTRICT | 1 | 62 | 1 |00:00:00.01 | 1 | | | |
|* 8 | FILTER | | 1 | | 221 |00:00:00.10 | 577 | | | |
|* 9 | FILTER | | 1 | | 221 |00:00:00.10 | 577 | | | |
| 10 | TABLE ACCESS BY INDEX ROWID| BMSQL_ORDER_LINE | 1 | 2500 | 31249 |00:00:00.02 | 577 | | | |
|* 11 | INDEX RANGE SCAN | BMSQL_ORDER_LINE_PKEY | 1 | 2500 | 31249 |00:00:00.01 | 106 | | | |
|* 12 | INDEX UNIQUE SCAN | BMSQL_STOCK_PKEY | 220 | 1 | 220 |00:00:00.01 | 662 | | | |
|* 13 | TABLE ACCESS BY INDEX ROWID | BMSQL_STOCK | 220 | 103 | 4 |00:00:00.01 | 232 | | | |
--------------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
7 - access("BMSQL_DISTRICT"."D_ID"=:SYS_B_5 AND "BMSQL_DISTRICT"."D_W_ID"=:SYS_B_4)
8 - filter("OL_O_ID"<"D_NEXT_O_ID")
9 - filter("OL_O_ID">="D_NEXT_O_ID"-:SYS_B_3)
11 - access("OL_W_ID"=:SYS_B_4 AND "OL_D_ID"=:SYS_B_5)
12 - access("S_I_ID"="OL_I_ID" AND "S_W_ID"=:SYS_B_1)
13 - filter("S_QUANTITY"<:SYS_B_2)
Note
-----
- dynamic sampling used for this statement (level=6)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
828 consistent gets
2 physical reads
0 redo size
525 bytes sent via SQL*Net to client
524 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
多块读取与索引/表扫描有关,但是在我看来,更改后的表不需要完全扫描操作。希望有人能为我解释这个问题。预先感谢。
更新:取消对DISTRICT
表的集群操作后,其运行速度很快
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 2385307489
------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 802 | | | |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.01 | 802 | | | |
| 2 | NESTED LOOPS | | 1 | | 9 |00:00:00.01 | 802 | | | |
| 3 | NESTED LOOPS | | 1 | 137 | 191 |00:00:00.02 | 605 | | | |
| 4 | VIEW | VW_NSO_1 | 1 | 6 | 191 |00:00:00.01 | 30 | | | |
| 5 | HASH UNIQUE | | 1 | 1 | 191 |00:00:00.01 | 30 | 1397K| 1397K| 1321K (0)|
| 6 | NESTED LOOPS | | 1 | 6 | 195 |00:00:00.02 | 30 | | | |
| 7 | TABLE ACCESS BY INDEX ROWID| BMSQL_DISTRICT | 1 | 1 | 1 |00:00:00.01 | 3 | | | |
|* 8 | INDEX UNIQUE SCAN | BMSQL_DISTRICT_PKEY | 1 | 1 | 1 |00:00:00.01 | 2 | | | |
| 9 | TABLE ACCESS BY INDEX ROWID| BMSQL_ORDER_LINE | 1 | 6 | 195 |00:00:00.02 | 27 | | | |
|* 10 | INDEX RANGE SCAN | BMSQL_ORDER_LINE_PKEY | 1 | 383 | 195 |00:00:00.01 | 4 | | | |
|* 11 | INDEX UNIQUE SCAN | BMSQL_STOCK_PKEY | 191 | 1 | 191 |00:00:00.01 | 575 | | | |
|* 12 | TABLE ACCESS BY INDEX ROWID | BMSQL_STOCK | 191 | 137 | 9 |00:00:00.01 | 197 | | | |
------------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
8 - access("BMSQL_DISTRICT"."D_W_ID"=:SYS_B_4 AND "BMSQL_DISTRICT"."D_ID"=:SYS_B_5)
10 - access("OL_W_ID"=:SYS_B_4 AND "OL_D_ID"=:SYS_B_5 AND "OL_O_ID">="D_NEXT_O_ID"-:SYS_B_3 AND "OL_O_ID"<"D_NEXT_O_ID")
11 - access("S_I_ID"="OL_I_ID" AND "S_W_ID"=:SYS_B_1)
12 - filter("S_QUANTITY"<:SYS_B_2)
Note
-----
- dynamic sampling used for this statement (level=6)
43 rows selected.