2014年12月1日月曜日

12.1.0.2 Zone Maps 入門 Part II

今回の記事は、JPOUGアドベントカレンダーと弊社バルテックのアドベントカレンダーにダブルエントリーしました。
http://jpoug.doorkeeper.jp/events/17313
http://www.adventar.org/calendars/414


この記事はOracle Ace DirectorのRichard Foote氏のご厚意で氏のブログを翻訳しています。
https://richardfoote.wordpress.com/2014/10/30/12-1-0-2-introduction-to-zone-maps-part-ii-changes/

この記事に関する指摘は、sakitaまでご連絡お願い致します。
また、翻訳は自動翻訳を若干意訳した程度のレベルとなっております。

日本語訳:sakita

==========

Part Iでは、Zone MapはExadataのStorage Indexに類似した構造のような新しいインデックスであることを議論しました。
Zone Mapは、表の各「ゾーン」を選択した列の最小値と最大値を格納することによって、テーブルのアクセス時にディスクブロックの「プルーニング」を可能にします。
各ゾーンは連続した8Mのブロックの範囲です。
Zone Mapは比較的小さいですが、よくクラスタ化された列(ALBUM_ID)のconsistent getsを減らすのに非常に有効であることを紹介しました。
この記事では引き続きデモを行い、テーブルにデータがアップデートされたとき、Zone Mapの場所に何が起きるのかを見て行きます。

では、いくつかの行(IDの値が1から100のもの)のALBUM_ID列(現在Zone Mapが定義されている)を更新していきましょう。
ALBUM_ID列の値はこれらの行ではすべて1であったのを142に更新します。


SQL> update big_bowie set album_id=142 where id between 1 and 100;

100 rows updated.

SQL> commit;

Commit complete.


さて、ALBUM_IDの最大の値は今142であり、100ではありません。現在のZone Mapにリストされている最大値を見てみましょう。


SQL> select max(max_1_album_id) from  big_bowie_album_id_zm;

MAX(MAX_1_ALBUM_ID)
-------------------
100


最大値はまだ100のままです。従いまして、実際にはZone Mapの内容は更新されていません。Zone Mapと従来のインデックスの間には大きな違いがあり、インデックスはDML操作中に自動的に更新されるのに対し、Zone Mapは更新されません(REFRESH ON COMMIT設定が指定されない限り)。


最小値が1(更新前のALBUM_ID列の値)のZone Mapエントリの状態を見ましょう。


SQL> select * from big_bowie_album_id_zm where min_1_album_id = 1;

ZONE_ID$ MIN_1_ALBUM_ID MAX_1_ALBUM_ID ZONE_LEVEL$ ZONE_STATE$ ZONE_ROWS$
---------- -------------- -------------- ----------- ----------- ----------
3.8586E+11              1              2           0           0      66234
3.8586E+11              1              2           0           1      65787
3.8586E+11              1              2           0           0      66223


ZONE_STATE$が失効したという意味の「1」になっていることが確認できます。しかし、他のゾーンはすべてまだOKです。

全体のZone Mapの状況を見ましょう。


SQL> select zonemap_name, pruning, refresh_mode, invalid, stale, unusable
from dba_zonemaps where zonemap_name='BIG_BOWIE_ALBUM_ID_ZM';

ZONEMAP_NAME              PRUNING  REFRESH_MODE      INVALID STALE   UNUSABLE
------------------------- -------- ----------------- ------- ------- --------
BIG_BOWIE_ALBUM_ID_ZM     ENABLED  LOAD DATAMOVEMENT NO      NO      NO


Zone Mapは更新後も"すべてOK"のままです。(注釈:変更されていないと言っていると思われます)

Part Iのクエリをリランします。


SQL> select * from big_bowie where album_id = 42;

100000 rows selected.

Elapsed: 00:00:00.29

Execution Plan
----------------------------------------------------------
Plan hash value: 1980960934

----------------------------------------------------------------------------------------------------
| Id  | Operation                              | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                       |           |   100K|  8984K|  3269  (12)| 00:00:01 |
|*  1 |  TABLE ACCESS STORAGE FULL WITH ZONEMAP| BIG_BOWIE |   100K|  8984K|  3269  (12)| 00:00:01 |
----------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------

1 - storage("ALBUM_ID"=42)
filter(SYS_ZMAP_FILTER('/* ZM_PRUNING */ SELECT "ZONE_ID$", CASE WHEN
BITAND(zm."ZONE_STATE$",1)=1 THEN 1 ELSE CASE WHEN (zm."MIN_1_ALBUM_ID" > :1 OR
zm."MAX_1_ALBUM_ID" < :2) THEN 3 ELSE 2 END END FROM "BOWIE"."BIG_BOWIE_ALBUM_ID_ZM" zm
WHERE zm."ZONE_LEVEL$"=0 ORDER BY zm."ZONE_ID$"',SYS_OP_ZONE_ID(ROWID),42,42)<3 AND "ALBUM_ID"=42)
Statistics
----------------------------------------------------------
141  recursive calls
0  db block gets
3238  consistent gets
0  physical reads
0  redo size
3130019  bytes sent via SQL*Net to client
761  bytes received via SQL*Net from client
21  SQL*Net roundtrips to/from client
0  sorts (memory)
0  sorts (disk)
100000  rows processed

Zone MapはまだCBOを使用しています。古くなったゾーンに関連付けられたすべてのブロックにより追加のアクセスが発生し、consistent getsの数は増えて(2364から3238)いますが、テーブル全体からすべてのブロックを読むよりは効率的です。
古いゾーンのエントリを削除したい場合は、Zone Mapを更新したり、再構築(ON DEMAND設定によるリフレッシュ)します。

SQL> alter materialized zonemap big_bowie_album_id_zm rebuild;

Materialized zonemap altered.

Zone Mapのエントリを見てみましょう。


SQL> select * from big_bowie_album_id_zm where min_1_album_id = 1;

ZONE_ID$ MIN_1_ALBUM_ID MAX_1_ALBUM_ID ZONE_LEVEL$ ZONE_STATE$ ZONE_ROWS$
---------- -------------- -------------- ----------- ----------- ----------
3.8586E+11              1              2           0           0      66234
3.8586E+11              1            142           0           0      65787
3.8586E+11              1              2           0           0      66223

エントリが古くないことと実際の最大値を反映した正しいゾーン(142)が確認できます。

クエリをリランしましょう。

SQL> select * from big_bowie where album_id = 42;

100000 rows selected.

Elapsed: 00:00:00.30

Execution Plan
----------------------------------------------------------
Plan hash value: 1980960934

----------------------------------------------------------------------------------------------------
| Id  | Operation                              | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                       |           |   100K|  8984K|  3269  (12)| 00:00:01 |
|*  1 |  TABLE ACCESS STORAGE FULL WITH ZONEMAP| BIG_BOWIE |   100K|  8984K|  3269  (12)| 00:00:01 |
----------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------

1 - storage("ALBUM_ID"=42)
filter(SYS_ZMAP_FILTER('/* ZM_PRUNING */ SELECT "ZONE_ID$", CASE WHEN
BITAND(zm."ZONE_STATE$",1)=1 THEN 1 ELSE CASE WHEN (zm."MIN_1_ALBUM_ID" > :1 OR
zm."MAX_1_ALBUM_ID" < :2) THEN 3 ELSE 2 END END FROM "BOWIE"."BIG_BOWIE_ALBUM_ID_ZM" zm
WHERE zm."ZONE_LEVEL$"=0 ORDER BY zm."ZONE_ID$"',SYS_OP_ZONE_ID(ROWID),42,42)<3 AND "ALBUM_ID"=42)
Statistics
----------------------------------------------------------
141  recursive calls
0  db block gets
3238  consistent gets
0  physical reads
0  redo size
3130019  bytes sent via SQL*Net to client
761  bytes received via SQL*Net from client
21  SQL*Net roundtrips to/from client
0  sorts (memory)
0  sorts (disk)
100000  rows processed

Zone Mapはまだ使用されていますが、consistent getsは前と変わらない値であり、何も変わっていないことに気がつきますでしょうか。なぜ以前の2364に戻っていないのでしょうか。
現在、更新されたゾーンのなかで取りうる値の範囲は1~142であり、42の要求値は潜在的にこのゾーン内に見つけられそうですので、念のためにアクセスする必要がまだあります。
私たちは42の値はこのゾーン内には存在しないことはわかっていますが、Oracleはそれを知ることはできず、1~142の範囲に基づいて処理されます。
従って、Zone Mapはデータが十分にクラスタ化され、ゾーンの最小値/最大値の範囲がアクセスする必要のあるゾーンを制限できるときに最適に動作します。もしデータが十分にクラスタ化されておらず、各ゾーンが(テーブル全体の)最小値と最大値をほとんど持っていた場合は、Oracleは効果的に多くまたはすべてのゾーンをプルーニングすることができませんし、Zone Mapは役に立たないでしょう。

また PART IIIで。

0 件のコメント:

コメントを投稿