« 2019年2月 | トップページ

2019年3月25日 (月)

Temp落ち #10 - パーティションワイズジョインはどうよ

Temp落ちシリーズ、久々ですが、今回は、そもそもメモリーに乗り切らないなら、一時表領域に落ちる量をなんとかできないのか。。。というおはなし

pgaとして利用できるメモリーサイズには限界もありますし、その範囲のデータサイズで、ずーーーーーつと収まっていてくれていればいいですが、そうじゃない状況のほうが圧倒的に多いのではないでしょうか。
であれば、オンメモリーで処理させようなんて考えずに、ある程度落ちることは仕方ないと諦め、一時表領域の利用サイズを減らせないか。。。その方法の一つがパーティションワイズジョイン
ただし、パーティションを利用するので、Enterprise Editionでしか使えません。それ以外の場合は。。。別の手を考えるとか。。。方法は少ないですけど。。(それは別の機会にでも。。)


では、非パーティション表とパーティション表のパーティシィンワイズジョインのPGAの使い方の差異を確認してみましょう。
思いつきで作ったにしてもよくない例ではりますが(やっつけ感満載wで、セグメントサイズを稼いでぐための表定義となっています)PGAの利用サイズの変化は見ることができると思います。

非パーティション表の定義と統計情報取得、それに登録した各表のセグメントサイズは以下のとおり。

create table m
(
id number(10) not null
,foo varchar2(4000)
,bar varchar2(4000)
,constraint pk_m primary key(id) using index
);


create table d
(
id number(10) not null
,rev# number(3) not null
,foo varchar2(4000)
,bar varchar2(4000)
,constraint pk_d primary key(id, rev#) using index
);

SCOTT> exec dbms_stats.gather_table_stats(ownname=>'SCOTT',tabname=>'M',cascade=>true,no_invalidate=>false);
SCOTT> exec dbms_stats.gather_table_stats(ownname=>'SCOTT',tabname=>'D',cascade=>true,no_invalidate=>false);

SCOTT> select segment_name,bytes/1024/1024 "MB" from user_segments where segment_name in ('M','D')

SEGMENT_NAME MB
------------------------------ ----------
M 192
D 3766

1つの操作で利用可能なPGAサイズは約80MBにしてあります。この状態で上記の2表を結合すれば、いい感じで一時表領域へ落ちるはずです。

SCOTT> select * from v$pgastat;

NAME VALUE UNIT CON_ID
---------------------------------------------------------------- ---------- ------------ ----------
・・・略・・・
global memory bound 83886080 bytes 0
・・・略・・・

2表をハッシュ結合するようにヒントで強制しています。
想定通り、PGAを使いきっても足りずに、580MBほど一時表猟奇が利用されています。

SQL Monitoring Report

SQL Text
------------------------------
SELECT /*+ MONITOR LEADING(m d) USE_HASH(m d) */ * FROM m INNER JOIN d ON m.id = d.id

Global Information
------------------------------
Status : DONE (ALL ROWS)
Instance ID : 1
Session : SCOTT (302:21504)
SQL ID : 44pfxjgnt7bcq
SQL Execution ID : 16777216
Execution Started : 03/24/2019 09:40:48
First Refresh Time : 03/24/2019 09:40:48
Last Refresh Time : 03/24/2019 09:41:07
Duration : 19s
Module/Action : SQL*Plus/-
Service : orcl
Program : sqlplus@localhost.localdomain (TNS V1-V3)
Fetch Calls : 16001

Global Stats
===========================================================================================
| Elapsed | Cpu | IO | Other | Fetch | Buffer | Read | Read | Write | Write |
| Time(s) | Time(s) | Waits(s) | Waits(s) | Calls | Gets | Reqs | Bytes | Reqs | Bytes |
===========================================================================================
| 11 | 4.41 | 5.53 | 1.28 | 16001 | 777K | 217K | 6GB | 2292 | 555MB |
===========================================================================================

SQL Plan Monitoring Details (Plan Hash Value=1876521935)
=====================================================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Write | Write | Mem | Temp | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | Reqs | Bytes | (Max) | (Max) | (%) | (# samples) |
=====================================================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 19 | +1 | 1 | 240K | | | | | . | . | 10.00 | Cpu (1) |
| 1 | HASH JOIN | | 240K | 232K | 19 | +1 | 1 | 240K | 2292 | 555MB | 2292 | 555MB | 84MB | 579MB | 60.00 | Cpu (1) |
| | | | | | | | | | | | | | | | | direct path write temp (5) |
| 2 | TABLE ACCESS FULL | M | 12000 | 6609 | 1 | +1 | 1 | 12000 | 4344 | 219MB | | | . | . | | |
| 3 | TABLE ACCESS FULL | D | 240K | 130K | 16 | +1 | 1 | 240K | 210K | 5GB | | | . | . | 30.00 | Cpu (1) |
| | | | | | | | | | | | | | | | | db file sequential read (2) |
=====================================================================================================================================================================================

パーティションワーズジョインが行われ、かつ、PGAにおさまりそうなサイズ以下になるようにハッシュパーティション化した表を作成し、同じデータ量を登録しました。
この例では8パーティションにしています。

表定義と時計情報取得及

create table m
(
id number(10) not null
,foo varchar2(4000)
,bar varchar2(4000)
,constraint pk_m primary key(id) using index
)
PARTITION BY HASH (id)
(
PARTITION m_p1
,PARTITION m_p2
,PARTITION m_p3
,PARTITION m_p4
,PARTITION m_p5
,PARTITION m_p6
,PARTITION m_p7
,PARTITION m_P8
);


create table d
(
id number(10) not null
,rev# number(3) not null
,foo varchar2(4000)
,bar varchar2(4000)
,constraint pk_d primary key(id, rev#) using index
)
PARTITION BY HASH (id)
(
PARTITION d_p1
,PARTITION d_p2
,PARTITION d_p3
,PARTITION d_p4
,PARTITION d_p5
,PARTITION d_p6
,PARTITION d_p7
,PARTITION d_P8
);

SQL> exec dbms_stats.gather_table_stats(ownname=>'SCOTT',tabname=>'M',cascade=>true,no_invalidate=>false,granularity=>'ALL',degree=>4);
SQL> exec dbms_stats.gather_table_stats(ownname=>'SCOTT',tabname=>'D',cascade=>true,no_invalidate=>false,granularity=>'ALL',degree=>4);


8分割のハッシュパーティション化したのでパーティション単位のセグメントサイズも随分小さくなりました。

SCOTT> select segment_name,partition_name,bytes/1024/1024 "MB" from user_segments where segment_name in ('M','D') order by 1,2;

SEGMENT_NAME PARTITION_NAME MB
------------------------------ ------------------------------ ----------
D D_P1 490
D D_P2 440
D D_P3 480
D D_P4 440
D D_P5 440
D D_P6 512
D D_P7 496
D D_P8 512
M M_P1 32
M M_P2 24
M M_P3 24
M M_P4 24
M M_P5 24
M M_P6 32
M M_P7 32
M M_P8 32


実行しているSQL文は同じですが、表はハッシュパーティションでぞれぞれ 1/8程度のサイズです。
結果を見ると、最大PGAサイズは、14MB、一時表領域はまだ利用されていますが、13MBと大きく削減できたことがわかると思います。
(パーティションワイズジョインの実行計画は独特なのでこの形を想えておいてください。NOTE等でパーティションワイズジョインが行われていることを示すコメント表示されません)

SQL Monitoring Report

SQL Text
------------------------------
SELECT /*+ MONITOR LEADING(m d) USE_HASH(m d) */ * FROM m INNER JOIN d ON m.id = d.id

Global Information
------------------------------
Status : DONE (ALL ROWS)
Instance ID : 1
Session : SCOTT (302:21504)
SQL ID : 44pfxjgnt7bcq
SQL Execution ID : 16777217
Execution Started : 03/24/2019 09:49:55
First Refresh Time : 03/24/2019 09:49:55
Last Refresh Time : 03/24/2019 09:50:08
Duration : 13s
Module/Action : SQL*Plus/-
Service : orcl
Program : sqlplus@localhost.localdomain (TNS V1-V3)
Fetch Calls : 16001

Global Stats
============================================================================================
| Elapsed | Cpu | IO | Other | Fetch | Buffer | Read | Read | Write | Write |
| Time(s) | Time(s) | Waits(s) | Waits(s) | Calls | Gets | Reqs | Bytes | Reqs | Bytes |
============================================================================================
| 4.90 | 1.62 | 1.56 | 1.72 | 16001 | 774K | 12322 | 4GB | 278 | 33MB |
============================================================================================

SQL Plan Monitoring Details (Plan Hash Value=1935477735)
======================================================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Write | Write | Mem | Temp | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | Reqs | Bytes | (Max) | (Max) | (%) | (# samples) |
======================================================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 14 | +0 | 1 | 240K | | | | | . | . | 25.00 | Cpu (1) |
| 1 | PARTITION HASH ALL | | 240K | 235K | 14 | +0 | 1 | 240K | | | | | . | . | | |
| 2 | HASH JOIN | | 240K | 235K | 14 | +0 | 8 | 240K | 278 | 33MB | 278 | 33MB | 14MB | 13MB | 25.00 | direct path write temp (1) |
| 3 | TABLE ACCESS FULL | M | 12000 | 7647 | 13 | +0 | 8 | 12000 | 384 | 189MB | | | . | . | | |
| 4 | TABLE ACCESS FULL | D | 240K | 131K | 14 | +0 | 8 | 240K | 11660 | 4GB | | | . | . | 50.00 | Cpu (1) |
| | | | | | | | | | | | | | | | | direct path read (1) |
======================================================================================================================================================================================


SQLモニターの結果からは明らかですが、v$sesstatからpga/ugaサイズが最大との程度利用されたか確認しておきます。(違いはパーティション化してパーティションワーズジョインしたかしないかという差です)
パーティションなし

       SID STATNAME                                                              VALUE
---------- ---------------------------------------------------------------- ----------
182 session uga memory 16561304
182 session uga memory max 90435464
182 session pga memory 26904760
182 session pga memory max 95717560


パーティション化 (8ハッシュパーティションにほぼ均一分割)

       SID STATNAME                                                              VALUE
---------- ---------------------------------------------------------------- ----------
182 session uga memory 17128696
182 session uga memory max 17250296
182 session pga memory 19564728
182 session pga memory max 19630264

temp落ちが辛い結合にであったら、ワーティション化とパーティションワイズジョインが利用できないか検証してみるのもありではないでしょうか?(EEに限りますが)


桜が咲き始めた、目黒川をランチタイムに散歩するか。。。

では、また。



Mac De Oracle なんですが、Windows(32bit)でのOracleな話
Mac De Oracle なんですが、Windows(32bit)でのOracleな話 #2
Mac De Oracle なんですが、Windows(32bit)でのOracleな話 #3
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #1
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #2
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #3
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #4
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #5
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #6
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #7
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #8
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #9
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #10
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #11
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #12
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #13
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #14
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #15
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #16
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #17
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #18
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? #19
_pga_max_sizeってOracle11gではどうなったっけ? という確認。
_pga_max_sizeってOracle11gではどうなったっけ? という確認。シーズン2
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? Season2 #1
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? Season2 #2
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? Season2 #3
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? Season2 #4
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? Season2 #5
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? Season2 #6
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? Season2 #7
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? Season2 #8
pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? Season2 #8

Temp落ち #1 - "Temp落ち" って?
Temp落ち #2 - PGA (Program Global Area)
Temp落ち #3 - 手動PGA管理で作業領域として指定可能な最大サイズ
Temp落ち #4 - 手動PGA管理で作業領域として指定可能な最大サイズ de Temp落ちの確認
Temp落ち #5 - pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? 12.2.0.1版 (その前に少し脱線)
Temp落ち #6 - pga_aggregate_targetでPGA?、_pga_max_sizeでPGA? 12.2.0.1版
Temp落ち #7 - 自動PGA管理で到達可能な最大サイズ de Temp落ちの確認 12.2.0.1版
Temp落ち #8 - 自動PGA管理でパラメータ上設定可能な最大サイズは?(実際に利用可能なサイズとは限りませんが。意味深) 12.2.0.1版
Temp落ち #9 - 自動PGA管理で_pga_max_sizeと戯れたPGAサイズって本当に使えるのか? 12.2.0.1版

| | コメント (0)

2019年3月24日 (日)

Oracle VM VirtualBox 6.0 でも治ってなかった、ドラッグするとDesktopが取り残される問題 / FAQ

Oracle VM VirtualBox 5.x台からあった問題、6.0でも修正されていないですね。
ただ、解決方法はあって、一旦、Dockにしまって再度取り出すと症状は治まるんですよね。これw

以下、タイトルバーをクリックしてドラッグするとなぜかデスクトップだけが取り残されてのっぺらぼう状態になってしまったスクリーンショット

20190324-152727

| | コメント (0)

2019年3月22日 (金)

ORA_HASH()を使ってリストパーティションにハッシュパーティションのような均一配分を

ハッシュパーティションってリストパーティションみたいにパーティション狙い撃ちできて、かつ、ハッシュパーティションみたいに、データをパーティション間で均一化できないのかなぁ
というずいぶん昔の話を思い出して、そう言えば書いてないかもしれない。いつの話だよってぐらい昔の話だけどw
どうやったかというと、
ハッシュキーにふさわしい値をもつ列を決める(一意キーとか主キー列が理想、カーディナリティの低い、分布に偏りのあるデータを持つ列は使わない)

で、ハッシュキーが決まったら、話は早くて、ORA_HASH()関数で取得できるハッシュ値を利用したリストパーティションを作成するだけ。
ゴニョゴニュ言わなくても、SQLとPL/SQLのコードを見ていただければ、理解していただけるかと。

ORCL@SCOTT> l
1 CREATE TABLE list_p_tab
2 (
3 id_code VARCHAR2(10) NOT NULL
4 , foo VARCHAR2(30)
5 , id_code_hash_value NUMBER(2) NOT NULL
6 )
7 PARTITION BY LIST (id_code_hash_value)
8 (
9 PARTITION list_p_tab_p1 VALUES(0)
10 ,PARTITION list_p_tab_p2 VALUES(1)
11 ,PARTITION list_p_tab_p3 VALUES(2)
12 ,PARTITION list_p_tab_p4 VALUES(3)
13* )
ORCL@SCOTT> /

Table created.

ORCL@SCOTT> ALTER TABLE list_p_tab ADD CONSTRAINT gpk_list_p_tab PRIMARY KEY(id_code) USING INDEX GLOBAL;

Table altered.

ORCL@SCOTT> l
1 DECLARE
2 TYPE id_code_t IS TABLE OF list_p_tab.id_code%TYPE INDEX BY PLS_INTEGER;
3 TYPE foo_t IS TABLE OF list_p_tab.foo%TYPE INDEX BY PLS_INTEGER;
4 id_codes id_code_t;
5 foos foo_t;
6 k PLS_INTEGER := 1;
7 BEGIN
8 FOR i IN 1..400000 LOOP
9 id_codes(k) := TO_CHAR(i,'fm0000000009');
10 foos(k) := i;
11 k := k + 1;
12 IF k > 1000 THEN
13 FORALL j in 1..k-1
14 INSERT INTO list_p_tab VALUES(id_codes(j), foos(j), ORA_HASH(id_codes(j),3));
15 COMMIT;
16 k := 1;
17 END IF;
18 END LOOP;
19* END;
ORCL@SCOTT> /

PL/SQL procedure successfully completed.

Elapsed: 00:00:12.28

ORCL@SCOTT> exec dbms_stats.gather_table_stats(ownname=>'SCOTT',tabname=>'LIST_P_TAB',granularity=>'ALL',cascade=>true,no_invalidate=>false,degree=>4);

PL/SQL procedure successfully completed.

Elapsed: 00:00:02.51

ORCL@SCOTT> r
1 select
2 table_name
3 ,partition_name
4 ,num_rows
5 from
6 user_tab_partitions
7 where
8 table_name = 'LIST_P_TAB'
9 order by
10* 1,2

TABLE_NAME PARTITION_NAME NUM_ROWS
------------------------------ ------------------------------ ----------
LIST_P_TAB LIST_P_TAB_P1 99901
LIST_P_TAB LIST_P_TAB_P2 100194
LIST_P_TAB LIST_P_TAB_P3 100056
LIST_P_TAB LIST_P_TAB_P4 99849

ORCL@SCOTT> select id_code_hash_value,count(1) from list_p_tab group by id_code_hash_value order by 1;

ID_CODE_HASH_VALUE COUNT(1)
------------------ ----------
0 99901
1 100194
2 100056
3 99849

Elapsed: 00:00:00.06

ORCL@SCOTT> explain plan for
2 select
3 *
4 from
5 list_p_tab
6 where
7 id_code_hash_value = 1;

Explained.

Elapsed: 00:00:00.10
ORCL@SCOTT> @?/rdbms/admin/utlxpls

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Plan hash value: 2143708561

----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 100K| 2054K| 275 (1)| 00:00:01 | | |
| 1 | PARTITION LIST SINGLE| | 100K| 2054K| 275 (1)| 00:00:01 | 2 | 2 |
| 2 | TABLE ACCESS FULL | LIST_P_TAB | 100K| 2054K| 275 (1)| 00:00:01 | 2 | 2 |
----------------------------------------------------------------------------------------------------

グローバル索引を作成してあるので、パーティション関係ない検索は主キー索引経由でも可。

ORCL@SCOTT> explain plan for select * from list_p_tab where id_code = '00004000000';

Explained.

Elapsed: 00:00:00.02
ORCL@SCOTT> @?/rdbms/admin/utlxpls

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------------------------
Plan hash value: 4132161764

---------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
---------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 21 | 3 (0)| 00:00:01 | | |
| 1 | TABLE ACCESS BY GLOBAL INDEX ROWID| LIST_P_TAB | 1 | 21 | 3 (0)| 00:00:01 | ROWID | ROWID |
|* 2 | INDEX UNIQUE SCAN | GPK_LIST_P_TAB | 1 | | 2 (0)| 00:00:01 | | |
---------------------------------------------------------------------------------------------------------------------

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

2 - access("ID_CODE"='00004000000')

| | コメント (0)

2019年3月21日 (木)

in-memory関連の謎パラメータ 18c

12cR2と18cのin-memory関連の隠しパラメータ以外の違い。
Database Reference Release 18
inmemory_optimized_arithmeticってパラメータ、SIMD向け最適化っぽい(デフォがDESABLEDみたいだが)
inmemory_prefer_xmem_memcompress と inmemory_prefer_xmem_priority inmemory_xmem_sizeこれらのパラメータ、隠しパラメータじゃないのにundocumented なのはなぜ?
もしかして、xmem って略語、Exadataの資料でヒットした。。。Exadata オンリー? なやつかな?
BANNER_LEGACY                                                                   BANNER                                                                          
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Oracle Database 18c Enterprise Edition Release 18.0.0.0.0 - Production Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production

ORCL@SYS> show parameter memory orcl12c@SYS> show parameter memory

NAME TYPE VALUE NAME TYPE VALUE
------------------------------------ ----------- ------------------------------ ------------------------------------ ----------- ------------------------------
hi_shared_memory_address integer 0 hi_shared_memory_address integer 0
inmemory_adg_enabled boolean TRUE inmemory_adg_enabled boolean TRUE
inmemory_automatic_level string OFF
inmemory_clause_default string inmemory_clause_default string
inmemory_expressions_usage string ENABLE inmemory_expressions_usage string ENABLE
inmemory_force string DEFAULT inmemory_force string DEFAULT
inmemory_max_populate_servers integer 0 inmemory_max_populate_servers integer 0
inmemory_optimized_arithmetic string DISABLE
inmemory_prefer_xmem_memcompress string
inmemory_prefer_xmem_priority string
inmemory_query string ENABLE inmemory_query string ENABLE
inmemory_size big integer 0 inmemory_size big integer 0
inmemory_trickle_repopulate_servers_ integer 1 inmemory_trickle_repopulate_servers_ integer 1
percent percent
inmemory_virtual_columns string MANUAL inmemory_virtual_columns string MANUAL
inmemory_xmem_size big integer 0
memory_max_target big integer 0 memory_max_target big integer 0
memory_target big integer 0 memory_target big integer 0
optimizer_inmemory_aware boolean TRUE optimizer_inmemory_aware boolean TRUE
shared_memory_address integer 0 shared_memory_address integer 0

| | コメント (0)

ハッシュパーティションでのデータの偏り / FAQ

ぼやき漫才みたいな感じですが、Oracleに限らず、ハッシュパーティションでパーティション間のデータを均一にしたいなら、ユニークな値かそれに準ずる列を選ぶべきなわけですが、なにを間違ってしまったのか、稀ではありますが、少々残念なことになっていすることもあります。
とは言え、早めに気づけば影響も小さくて済むわけで:)


というわけで、今回はそんなおはなし。

id_code列の値はユニーク
ORCL@SCOTT> select count(*),count(distinct id_code) from org;

COUNT(*) COUNT(DISTINCTID_CODE)
---------- ----------------------
400000 400000
type列の値は、一意性がなくカーディナリティーも低い、かつ、大きな偏りがある。。
ORCL@SCOTT> select type,count(1) from org group by type;

type COUNT(1)
---------- ----------
1 60000
2 60000
9 60000
0 220000
ハッシュパーティションを選択する主な理由は、パーティションへのデータの均一分散なので、列の値がユニークな列をパーティションキーとしてパーティション化することが多いわけですが、。。
以下は、ハッシュキーに一意な値を持つ列を選択した場合の例
ORCL@SCOTT> r
1 create table hash_p_tab
2 partition by hash(id_code)
3 (
4 partition hash_p_tab_p1
5 ,partition hash_p_tab_p2
6 ,partition hash_p_tab_p3
7 ,partition hash_p_tab_p4
8 )
9 as select
10 id_code
11 ,foo
12 ,type
13 from
14* org

Table created.

ORCL@SCOTT> alter table hash_p_tab add constraint gpk_hash_p_tab primary key(id_code) using index global;

Table altered.

ORCL@SCOTT> exec dbms_stats.gather_table_stats(ownname=>'SCOTT',tabname=>'hash_p_tab',cascade=>true,no_invalidate=>false,granularity=>'ALL');


ORCL@SCOTT> select table_name,partition_name,num_rows from user_tab_partitions order by 1,2;

TABLE_NAME PARTITION_NAME NUM_ROWS
------------------------------ ------------------------------ ----------
HASH_P_TAB HASH_P_TAB_P1 99901
HASH_P_TAB HASH_P_TAB_P2 100194
HASH_P_TAB HASH_P_TAB_P3 100056
HASH_P_TAB HASH_P_TAB_P4 99849


しかし、値の分布に偏りのあるカーディナリティの低い列を選んで残念なことになっているケースも稀にあったりします。

なぜ、ハッシュキーにこの列を選んだんだ! みたいな。。。

そんな時は、設計した人に聞くしかないです。何がやりたかったのかを。。。私に聞かれてもハッシュキーの選択をミスったんですよねーたぶん、としか言えないので。
ORCL@SCOTT> r
1 create table hash_p_tab_skew
2 partition by hash(type)
3 (
4 partition hash_p_tab_skew_p1
5 ,partition hash_p_tab_skew_p2
6 ,partition hash_p_tab_skew_p3
7 ,partition hash_p_tab_skew_p4
8 )
9 as select
10 id_code
11 ,foo
12 ,type
13 from
14* org

Table created.

ORCL@SCOTT> alter table hash_p_tab_skew add constraint gpk_hash_p_tab_skew primary key(id_code) using index global;

Table altered.

ORCL@SCOTT> exec dbms_stats.gather_table_stats(ownname=>'SCOTT',tabname=>'hash_p_tab_skew',cascade=>true,no_invalidate=>false,granularity=>'ALL');

PL/SQL procedure successfully completed.

ORCL@SCOTT> select table_name,partition_name,num_rows from user_tab_partitions where table_name = upper('hash_p_tab_skew') order by 1,2

TABLE_NAME PARTITION_NAME NUM_ROWS
------------------------------ ------------------------------ ----------
HASH_P_TAB_SKEW HASH_P_TAB_SKEW_P1 0
HASH_P_TAB_SKEW HASH_P_TAB_SKEW_P2 280000
HASH_P_TAB_SKEW HASH_P_TAB_SKEW_P3 60000
HASH_P_TAB_SKEW HASH_P_TAB_SKEW_P4 60000
で、データを均一にパーティションに分散させることをなんとなーく、イメージしつつ、上記のようなミスをしてしまうと、パラレルクエリーなどで最もデータの多いパーティションの処理時間に引っ張られて想定より処理時間が長くなるなんてことも。。。あるわけで
例がイケてないけど(気にしないでw)、パラレルサーバーのスレーブ間でbuffer gets部分を見ていただくと偏りはわかりやすいはず。(赤字部分):)
偏りあり
orcl2@SCOTT> @sql_skew
1 select
2 /*+
3 monitor
4 parallel(4)
5 */
6 count(1)
7 from
8 hash_p_tab_skew t01
9 inner join hash_p_tab_skew2 t02
10 on
11 t01.id_code = t02.id_code
12* and t01.type = t02.type


Parallel Execution Details (DOP=4 , Servers Allocated=4)
==========================================================================================
| Name | Type | Server# | Elapsed | Cpu | Other | Buffer | Wait Events |
| | | | Time(s) | Time(s) | Waits(s) | Gets | (sample #) |
==========================================================================================
| PX Coordinator | QC | | 0.02 | 0.00 | 0.02 | 72 | |
| p000 | Set 1 | 1 | 0.18 | 0.17 | 0.01 | 1940 | |
| p001 | Set 1 | 2 | 0.05 | 0.05 | 0.00 | 448 | |
| p002 | Set 1 | 3 | 0.05 | 0.05 | 0.00 | 448 | |
| p003 | Set 1 | 4 | 0.00 | 0.00 | 0.00 | | |
==========================================================================================

偏りの悪影響のイメージはこんな感じ
20190321-165450
20190321-165622

偏りなし
orcl2@SCOTT> @sql_noskew
1 select
2 /*+
3 monitor
4 parallel(4)
5 */
6 count(1)
7 from
8 hash_p_tab t01
9 inner join hash_p_tab2 t02
10 on
11 t01.id_code = t02.id_code
12* and t01.type = t02.type


Parallel Execution Details (DOP=4 , Servers Allocated=4)
==========================================================================================
| Name | Type | Server# | Elapsed | Cpu | Other | Buffer | Wait Events |
| | | | Time(s) | Time(s) | Waits(s) | Gets | (sample #) |
==========================================================================================
| PX Coordinator | QC | | 0.01 | 0.00 | 0.00 | 96 | |
| p000 | Set 1 | 1 | 0.08 | 0.08 | | 714 | |
| p001 | Set 1 | 2 | 0.08 | 0.08 | 0.00 | 714 | |
| p002 | Set 1 | 3 | 0.08 | 0.07 | 0.01 | 714 | |
| p003 | Set 1 | 4 | 0.08 | 0.08 | | 712 | |
==========================================================================================
パーティション毎にぞれぞれ得手不得手があります。そこんとこを把握したうえで、有効活用したいものですよね。(パーティションもいろいろ進化してきて便利になってきたわけですが、その分わかりにくいところも増えてきて理解するのに大変だったり 18cのも差分は把握しといたほうがいいかw...:)

| | コメント (0)

Join Elimination(結合の排除)と 参照整合性制約 / FAQ

偶に聞かれることがあるので、再び、Join Elimination(結合の排除)について
まずは、以下のSQL文を。
order表とcustomers表をinner joinしている単純な文ですが、重要なのは、実行計画の方!


order表とcustomers表をinner joinしているのに、order表だけ(この場合、order表の主キー索引だけのIndex Only Scanになっていますが)で、customes表を結合していせん。

理由は単純で、以下のSQL文では、customsers表の結合が不要なだけなんです。なぜかわかりますか?
以前、浅瀬でジャブジャブしていたセッション資料にヒントがあります。
order表に定義されている参照整合性制約によりcustomer_idがcustomsers表に存在していることを確認するための結合は不要と、オプティマイザーが判断した結果なんですよね。これ。
上記以外のケースでも無駄な結合を排除しようとする最適化を行うことがあります。内部的にはSQL文を書き換えてくれているわけですね。無駄に結合を行わないために。。。10053トレースをとって、 Join Elimination で grep をかけてみるとオプティマイザの気持ちが見えてきます:)
ORCL@OE> explain plan for
2 select
3 distinct
4 order_id
5 from
6 orders o
7 , customers c
8 where
9 o.customer_id = c.customer_id
10 and order_id < 2400;

Explained.

ORCL@OE> @?/rdbms/admin/utlxpls

PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------
Plan hash value: 1653993310

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

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

1 - access("ORDER_ID"<2400)
上記、SQL文は、参照整合性制約により、orders表に存在するcustomer_idがcustomers表に存在することが保証されているため、結合により存在確認が不要となり、Optimizerは内部的にSQL文を以下のように書き換えたということになります。賢いですよね。
ORCL@OE> r
1 explain plan for
2 select
3 distinct
4 order_id
5 from
6 orders o
7 where
8* order_id < 2400

Explained.

ORCL@OE> @?/rdbms/admin/utlxpls

PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------
Plan hash value: 1653993310

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

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

1 - access("ORDER_ID"<2400)

13 rows selected.


order表の参照整合性制約を確認しておきます。

ORCL@OE> r
1 select
2 table_name
3 ,owner
4 ,constraint_name
5 ,constraint_type
6 ,r_owner
7 ,r_constraint_name
8 ,status
9 ,rely
10 from
11 user_constraints
12 where
13* constraint_type='R'

TABLE_NAME OWNER CONSTRAINT_NAME C R_OWNER R_CONSTRAINT_NAME STATUS RELY
------------------------------ ------------------------------ ------------------------------ - ------------------------------ ------------------------------ -------- ----
ORDERS OE ORDERS_CUSTOMER_ID_FK R OE CUSTOMERS_PK ENABLED
INVENTORIES OE INVENTORIES_WAREHOUSES_FK R OE WAREHOUSES_PK ENABLED
INVENTORIES OE INVENTORIES_PRODUCT_ID_FK R OE PRODUCT_INFORMATION_PK ENABLED
ORDER_ITEMS OE ORDER_ITEMS_ORDER_ID_FK R OE ORDER_PK ENABLED
ORDER_ITEMS OE ORDER_ITEMS_PRODUCT_ID_FK R OE PRODUCT_INFORMATION_PK ENABLED
PRODUCT_DESCRIPTIONS OE PD_PRODUCT_ID_FK R OE PRODUCT_INFORMATION_PK ENABLED

ORCL@OE> r
1 select
2 table_name
3 ,column_name
4 ,constraint_name
5 from
6 user_cons_columns
7 where
8 table_name in ('ORDERS','CUSTOMERS')
9 order by
10* table_name

TABLE_NAME COLUMN_NAME CONSTRAINT_NAME
------------------------------ ------------------------------ ------------------------------
CUSTOMERS CUSTOMER_ID CUSTOMERS_PK
CUSTOMERS CUST_FIRST_NAME CUST_FNAME_NN
CUSTOMERS CUSTOMER_ID CUSTOMER_ID_MIN
CUSTOMERS CREDIT_LIMIT CUSTOMER_CREDIT_LIMIT_MAX
CUSTOMERS CUST_LAST_NAME CUST_LNAME_NN
ORDERS ORDER_ID ORDER_PK
ORDERS ORDER_TOTAL ORDER_TOTAL_MIN
ORDERS ORDER_MODE ORDER_MODE_LOV
ORDERS CUSTOMER_ID ORDER_CUSTOMER_ID_NN
ORDERS CUSTOMER_ID ORDERS_CUSTOMER_ID_FK
ORDERS ORDER_DATE ORDER_DATE_NN




Oracle SQL DeveloperでリバースエンジニアリングしたERDは以下のとおり

20190321-144842

では、最後に、参照整合性制約を無効化した場合、実行計画はどうなるか見ておきましょう。
ORCL@OE> alter table orders disable constraint orders_customer_id_fk;

Table altered.

ORCL@OE> r
1 select
2 table_name
3 ,owner
4 ,constraint_name
5 ,constraint_type
6 ,r_owner
7 ,r_constraint_name
8 ,status
9 ,rely
10 from
11 user_constraints
12 where
13* constraint_type='R'

TABLE_NAME OWNER CONSTRAINT_NAME C R_OWNER R_CONSTRAINT_NAME STATUS RELY
------------------------------ ------------------------------ ------------------------------ - ------------------------------ ------------------------------ -------- ----
ORDERS OE ORDERS_CUSTOMER_ID_FK R OE CUSTOMERS_PK DISABLED
INVENTORIES OE INVENTORIES_WAREHOUSES_FK R OE WAREHOUSES_PK ENABLED
INVENTORIES OE INVENTORIES_PRODUCT_ID_FK R OE PRODUCT_INFORMATION_PK ENABLED
ORDER_ITEMS OE ORDER_ITEMS_ORDER_ID_FK R OE ORDER_PK ENABLED
ORDER_ITEMS OE ORDER_ITEMS_PRODUCT_ID_FK R OE PRODUCT_INFORMATION_PK ENABLED
PRODUCT_DESCRIPTIONS OE PD_PRODUCT_ID_FK R OE PRODUCT_INFORMATION_PK ENABLED

あらまあ、不思議w わざとらしいw
customers表げ結合されちゃってネステッドループ結合に!
ORCL@OE> r
1 explain plan for
2 select
3 distinct
4 order_id
5 from
6 orders o
7 , customers c
8 where
9 o.customer_id = c.customer_id
10* and order_id < 2400

Explained.

ORCL@OE> @?/rdbms/admin/utlxpls

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------
Plan hash value: 2552081916

----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 46 | 552 | 3 (34)| 00:00:01 |
| 1 | SORT UNIQUE NOSORT | | 46 | 552 | 3 (34)| 00:00:01 |
| 2 | NESTED LOOPS SEMI | | 46 | 552 | 2 (0)| 00:00:01 |
|* 3 | TABLE ACCESS BY INDEX ROWID| ORDERS | 46 | 368 | 2 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | ORDER_PK | 46 | | 1 (0)| 00:00:01 |
|* 5 | INDEX UNIQUE SCAN | CUSTOMERS_PK | 319 | 1276 | 0 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------

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

3 - filter("O"."CUSTOMER_ID">0)
4 - access("ORDER_ID"<2400)
5 - access("O"."CUSTOMER_ID"="C"."CUSTOMER_ID")

目黒方面の密林で、美登利の寿司弁当を食べるのが最近のマイブームw
ではまた。

| | コメント (0)

2019年3月17日 (日)

Oracle VM VirtualBoxが6.0になってた

自分のことに気を取られて、ネットを泳ぎきれてない日が続いてるなーと思う今日この頃ですが、
また、一つ、遅れ気味で、気づいたw

VirtualBox 、 6.0になってたのでアップデートdone

https://www.virtualbox.org/wiki/Changelog-6.0#v4
https://www.virtualbox.org/wiki/Downloads

20190317_123051


| | コメント (0) | トラックバック (0)

2019年3月16日 (土)

Oracle Database入学式 2019 – 保護者の方はご遠慮ください

毎年恒例の
Oracle Database入学式 2019 – 保護者の方はご遠慮ください
https://jpoug.doorkeeper.jp/events/88273
が開催されます。

開催場所は エヌ・ティ・ティ・データ先端技術株式会社コラボレーションルーム です。

すでに満席となっていますが、キャンセル待ち登録可能です。

| | コメント (0) | トラックバック (0)