2014年12月25日木曜日

12.1.0.2 Zone Maps 入門 Part III

今回の記事は、弊社バルテックのアドベントカレンダーにエントリーしています。
http://www.adventar.org/calendars/414


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

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

日本語訳:sakita

==========

私は以前、新しいデータベース機能 Zone Mapが、どのようにExadata Storage Indexと同様の動きをしているのか説明をしてきました。
データが十分にZone Mapまたはインデックスと連携して良くクラスタ化されたときだけ、Storage Index(及び従来のインデックス)のように効果的に動くことを確認しました。
また、Zone Mapと同じデータがテーブルにあることにより、テーブル内の各8MBのZoneの最小値と最大値の範囲は可能な限り狭くすることができ、よりZoneへのアクセスを減らすことができます。
一方で、テーブル内のデータが十分にクラスタ化されていないときには、最小値と最大値のZone Mapの有効性は限定的となり、範囲は非常に広くなってしまいます。

このテーマの最初の記事で私が例に挙げたALBUM_ID列では、データが非常によくクラスタ化されていたため、関連したZone Mapは非常に有効でした。しかし、データのクラスタ化が不十分であった場合はどうでしたでしょうか?
例にあげるために、私は値がテーブル全体にランダムに分散している、不十分にクラスタ化されたARTIST_ID列にZone Mapを作成します。


SQL> create materialized zonemap big_bowie_artist_id_zm on big_bowie(artist_id);
 create materialized zonemap big_bowie_artist_id_zm on big_bowie(artist_id)
 *
 ERROR at line 1:
 ORA-31958: fact table "BOWIE"."BIG_BOWIE" already has a zonemap
 "BOWIE"."BIG_BOWIE_ALBUM_ID_ZM" on it


インデックスとZone Mapのもう一つの違いは、1つのZone Mapは、テーブルごとに定義されていますが、Zone Mapは複数の列を含めることができます。しかし、私は既にZone MapはALBUM_ID列のみに定義されてきたため、別のものを作成することはできません。

従いまして、私は現在のZone Mapを削除し、ARTIST_IDとALBUM_ID列の両方に基づいた新しいものを作成します:


SQL> drop materialized zonemap big_bowie_album_id_zm;

Materialized zonemap dropped.

SQL> create materialized zonemap big_bowie_zm on big_bowie(album_id, artist_id);

Materialized zonemap created.
   
 SQL> select measure, position_in_select, agg_function, agg_column_name
 from dba_zonemap_measures where zonemap_name='BIG_BOWIE_ZM';

MEASURE              POSITION_IN_SELECT AGG_FUNCTION  AGG_COLUMN_NAME
 -------------------- ------------------ ------------- --------------------
 "BOWIE"."BIG_BOWIE".                  5 MAX           MAX_2_ARTIST_ID
 "ARTIST_ID"

"BOWIE"."BIG_BOWIE".                  4 MIN           MIN_2_ARTIST_ID
 "ARTIST_ID"

"BOWIE"."BIG_BOWIE".                  3 MAX           MAX_1_ALBUM_ID
 "ALBUM_ID"

"BOWIE"."BIG_BOWIE".                  2 MIN           MIN_1_ALBUM_ID
 "ALBUM_ID"


この新しいゾーンマップはARTIST_IDとALBUM_ID列の両方にテーブル内の各ゾーンごとに最小値と最大値を持っています。

最小値/最大値のZone Mapの範囲は、データのクラスタリングの優れた視覚的な表現を提供しています。私はALBUM_ID列のZone Mapの詳細を選択した場合は(下のリストの一部を参照してください)。


SQL> select zone_id$, min_1_album_id, max_1_album_id, zone_rows$ from big_bowie_zm;

ZONE_ID$ MIN_1_ALBUM_ID MAX_1_ALBUM_ID ZONE_ROWS$
 ---------- -------------- -------------- ----------
 3.8586E+11              1              2      66234
 3.8586E+11              5              6      56715
 3.8586E+11              7              7      76562
 3.8586E+11              7              8      76632
 3.8586E+11              8              9      76633
 3.8586E+11             21             22      75615
 3.8586E+11             29             29      75582
 3.8586E+11             31             32      75545
 3.8586E+11             35             36      75617
 3.8586E+11             43             44      75615
 ...

3.8586E+11             76             77      75615
 3.8586E+11             79             80      75615
 3.8586E+11             86             87      75616
 3.8586E+11             88             89      75618
 3.8586E+11             97             97      75771
 3.8586E+11            100            100      15871

134 rows selected.


テーブル内のデータを効果的にALBUM_ID列に基づいて順序付けされます(非常に良くこの列に関連してクラスタ化されている)。各Zoneの最小値/最大値の範囲は極めて狭くなっています。各Zoneには基本的にALBUM_IDの1つまたは2つの異なる値が含まれ、もし特定のALBUM_IDの値だけであれば、Zone Mapは不要なZoneを排除するのに非常に有効です。我々が欲しいものだけです。
しかしながら、クラスタ化が不十分なARTIST_IDカラム(同じ一部分のリスト)のゾーンマップの詳細を見てみると:

SQL> select zone_id$, min_2_artist_id, max_2_artist_id, zone_rows$ from big_bowie_zm;

ZONE_ID$ MIN_2_ARTIST_ID MAX_2_ARTIST_ID ZONE_ROWS$
 ---------- --------------- --------------- ----------
 3.8586E+11            3661           98244      66234
 3.8586E+11               1          100000      56715
 3.8586E+11            5273           81834      76562
 3.8586E+11               1          100000      76632
 3.8586E+11               1          100000      76633
 3.8586E+11               1          100000      75615
 3.8586E+11            2383           77964      75582
 3.8586E+11               1          100000      75545
 3.8586E+11               1          100000      75617
 3.8586E+11               1          100000      75615
 ...

3.8586E+11               1          100000      75615
 3.8586E+11               1          100000      75615
 3.8586E+11               1          100000      75615
 3.8586E+11               1          100000      75615
 3.8586E+11               1          100000      75616
 3.8586E+11               1          100000      75618
 3.8586E+11            4848           80618      75771
 3.8586E+11           84130          100000      15871

134 rows selected.


Zoneのほとんどは範囲が非常に大きく、多くは実際に最小値が1(実際の最小値)で、最大値が100000(実際の最大)となっています。特定の要求値はZoneのほとんどに存在することとなり、最悪のシナリオです。それによってOracleに対してほとんどのZoneを確認するよう強制し、Zone Mapは完全に効果が無いことをとなります。
もし、特定のARTIST_IDに対して検索クエリを実行したとすると:

SQL> select * from big_bowie where artist_id=42;

100 rows selected.

Elapsed: 00:00:00.69

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

----------------------------------------------------------------------------------------------------
 | Id  | Operation                              | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
 ----------------------------------------------------------------------------------------------------
 |   0 | SELECT STATEMENT                       |           |    99 |  9108 |  3291  (13)| 00:00:01 |
 |*  1 |  TABLE ACCESS STORAGE FULL WITH ZONEMAP| BIG_BOWIE |    99 |  9108 |  3291  (13)| 00:00:01 |
 ----------------------------------------------------------------------------------------------------
 Predicate Information (identified by operation id):
 ---------------------------------------------------

1 - storage("ARTIST_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_2_ARTIST_ID" > :1 OR
 zm."MAX_2_ARTIST_ID" < :2) THEN 3 ELSE 2 END END FROM "BOWIE"."BIG_BOWIE_ZM" zm WHERE
 zm."ZONE_LEVEL$"=0 ORDER BY zm."ZONE_ID$"',SYS_OP_ZONE_ID(ROWID),42,42)<3 AND
 "ARTIST_ID"=42)

     
 Statistics
 ----------------------------------------------------------
 141  recursive calls
 0  db block gets
 101614  consistent gets
 0  physical reads
 0  redo size
 5190  bytes sent via SQL*Net to client
 618  bytes received via SQL*Net from client
 8  SQL*Net roundtrips to/from client
 0  sorts (memory)
 0  sorts (disk)
 100  rows processed


わずか100行の結果を返すために、101,614もの非常に高いconsistent getsを行うことを余儀なくされているのが確認できます。consistent getsが2364(訳注:効果的なZone Mapのときの値)よりもはるかに高く、100000行の結果をすべて返す際のconsistents gets 135,085と比較して大差ありません。
ARTIST_ID列に基づいてこれらのクエリのパフォーマンスを改善する必要があります...

このZone Mapを削除しましょう:


SQL> drop materialized zonemap big_bowie_zm;

Materialized zonemap dropped.

そして、ARTIST_ID行のデータ順にクラスタ化されるように物理的なクラスタリングを変更しましょう。


SQL> alter table big_bowie add clustering by linear order(artist_id, album_id) with materialized zonemap;

Table altered.


さて、このテーブルに新しいZone Mapを基にしたクラスタリング属性を追加します(以前の記事で説明しました)。


SQL> select zonemap_name from dba_zonemaps where fact_table='BIG_BOWIE';

ZONEMAP_NAME
---------------
ZMAP$_BIG_BOWIE

SQL> select zonemap_name, pruning, with_clustering, invalid, stale, unusable
from dba_zonemaps where zonemap_name = 'ZMAP$_BIG_BOWIE';

ZONEMAP_NAME    PRUNING  WITH_CLUSTERING INVALID STALE   UNUSABLE
--------------- -------- --------------- ------- ------- --------
ZMAP$_BIG_BOWIE ENABLED  YES             NO      NO      NO


実際にはテーブルを再編成していませんが、テーブル行は以前と同じようにクラスタ化されています。:

SQL> select zone_id$, min_2_album_id, max_2_album_id, zone_rows$ from zmap$_big_bowie;

ZONE_ID$ MIN_2_ALBUM_ID MAX_2_ALBUM_ID ZONE_ROWS$
---------- -------------- -------------- ----------
3.8586E+11             43             44      75615
3.8586E+11              1              2      66234
3.8586E+11             81             82      75615
3.8586E+11             29             29      75582
3.8586E+11             50             50      75481
3.8586E+11             90             91      75484
3.8586E+11              5              6      56715
3.8586E+11              7              8      76632
3.8586E+11              8              9      76633
3.8586E+11             16             16      75481
...

3.8586E+11             44             44      75480
3.8586E+11             82             83      75616
3.8586E+11            100            100      15871
3.8586E+11             34             35      75576
3.8586E+11             14             15      75615
3.8586E+11             33             34      75616
3.8586E+11              3              5      75707

134 rows selected.

SQL> select zone_id$, min_1_artist_id, max_1_artist_id, zone_rows$ from zmap$_big_bowie;

ZONE_ID$ MIN_1_ARTIST_ID MAX_1_ARTIST_ID ZONE_ROWS$
---------- --------------- --------------- ----------
3.8586E+11               1          100000      75545
3.8586E+11               1          100000      75616
3.8586E+11               1          100000      75617
3.8586E+11               1          100000      75911
3.8586E+11               1          100000      75616
3.8586E+11               1          100000      75616
3.8586E+11               1          100000      75615
3.8586E+11               1          100000      75616
3.8586E+11             132           75743      75612
3.8586E+11               1          100000      75615
...

3.8586E+11               1          100000      66296
3.8586E+11               1          100000      75615
3.8586E+11            2360           96960      75701
3.8586E+11               1          100000      75615
3.8586E+11               1          100000      75616
3.8586E+11           23432           98911      75480
3.8586E+11               1          100000      75791
3.8586E+11           21104           96583      75480

134 rows selected.

テーブルを再編成した場合でも、クラスタリング属性を有効にできるようにします:


SQL> alter table big_bowie move;

Table altered.

Zone Mapの特性が劇的に変化しているに気づくでしょう。以前に良くクラスタ化されたALBUM_ID列無効となり、すべての範囲を効果的に完全な最小値/最大値からなるZone Mapができています。



SQL> select zone_id$, min_2_album_id, max_2_album_id, zone_rows$ from zmap$_big_bowie;

ZONE_ID$ MIN_2_ALBUM_ID MAX_2_ALBUM_ID ZONE_ROWS$
---------- -------------- -------------- ----------
3.9704E+11              1            142      21185
3.9704E+11              1            100       9452
3.9704E+11              1            100      76516
3.9704E+11              1            100      75501
3.9704E+11              1            100      75497
3.9704E+11              1            100      75501
3.9704E+11              1            100      75499
3.9704E+11              1            100      75504
3.9704E+11              1            100      75500
3.9704E+11              1            100      75501
...

3.9704E+11              1            100      75503
3.9704E+11              1            100      75498
3.9704E+11              1            100      75501
3.9704E+11              1            100      75501
3.9704E+11              1            100      75501
3.9704E+11              1            100      75501
3.9704E+11              1            100      75794

144 rows selected.

ARTIST_ID列に以前にあった効果的でないZone Mapは、はるかに効果的な小さい範囲の最小値/最大値となっているZoneとなっています:

SQL> select zone_id$, min_1_artist_id, max_1_artist_id, zone_rows$ from zmap$_big_bowie;

ZONE_ID$ MIN_1_ARTIST_ID MAX_1_ARTIST_ID ZONE_ROWS$
---------- --------------- --------------- ----------
3.9704E+11              67            1036      21185
3.9704E+11            2359            2453       9452
3.9704E+11            8341            9106      76516
3.9704E+11           18933           19688      75501
3.9704E+11           22708           23463      75497
3.9704E+11           26483           27238      75501
3.9704E+11           27238           27993      75499
3.9704E+11           33278           34033      75504
3.9704E+11           36674           40449      75500
3.9704E+11           38563           39318      75501
...

3.9704E+11           49888           50643      75503
3.9704E+11           62723           63478      75498
3.9704E+11           77824           78579      75501
3.9704E+11           82354           83109      75501
3.9704E+11           88394           89149      75501
3.9704E+11           93679           94434      75501
3.9704E+11           98211           98969      75794

144 rows selected.


先ほどと同じクエリは、Zone Mapがアクセスされてから、ほぼすべてのZoneを排除することができるようになり、はるかに速く実行されます。



SQL> select * from big_bowie where artist_id=42;

100 rows selected.

Elapsed: 00:00:00.02

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

----------------------------------------------------------------------------------------------------
| Id  | Operation                              | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                       |           |    99 |  9108 |  3291  (13)| 00:00:01 |
|*  1 |  TABLE ACCESS STORAGE FULL WITH ZONEMAP| BIG_BOWIE |    99 |  9108 |  3291  (13)| 00:00:01 |
----------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------

1 - storage("ARTIST_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_ARTIST_ID" > :1 OR
zm."MAX_1_ARTIST_ID" < :2) THEN 3 ELSE 2 END END FROM "BOWIE"."ZMAP$_BIG_BOWIE" zm WHERE
zm."ZONE_LEVEL$"=0 ORDER BY zm."ZONE_ID$"',SYS_OP_ZONE_ID(ROWID),42,42)<3 AND
"ARTIST_ID"=42)
Statistics
----------------------------------------------------------
187  recursive calls
0  db block gets
175  consistent gets
0  physical reads
0  redo size
5190  bytes sent via SQL*Net to client
618  bytes received via SQL*Net from client
8  SQL*Net roundtrips to/from client
9  sorts (memory)
0  sorts (disk)
100  rows processed


consistent getsは以前の101,614から175に劇的に減少しています。
データのクラスタリングを変更すると、一つのことが改善される代わりにかなり悪い何かが共通して起きます。以前のALBUM_ID列に基づいた効率的なアクセスは以前と比較してどうでしょうか。


SQL> select * from big_bowie where album_id = 42;

100000 rows selected.

Elapsed: 00:00:01.27

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_2_ALBUM_ID" > :1 OR
zm."MAX_2_ALBUM_ID" < :2) THEN 3 ELSE 2 END END FROM "BOWIE"."ZMAP$_BIG_BOWIE" zm WHERE
zm."ZONE_LEVEL$"=0 ORDER BY zm."ZONE_ID$"',SYS_OP_ZONE_ID(ROWID),42,42)<3 AND "ALBUM_ID"=42)

Statistics
----------------------------------------------------------
187  recursive calls
0  db block gets
141568  consistent gets
0  physical reads
0  redo size
4399566  bytes sent via SQL*Net to client
73878  bytes received via SQL*Net from client
6668  SQL*Net roundtrips to/from client
9  sorts (memory)
0  sorts (disk)
100000  rows processed

今、consistent getsが以前の2,364からなんと、141,568に上昇しています。
従って、Zone Mapは、データベースのインデックスとのExadata Storage Indexのように、I/Oを減らすのに非常に有益でありますが、その有効性はデータのクラスタリングに非常に大きく依存をします。

2014年12月20日土曜日

sedとawkで一行シェルプログラミング

今回の記事は、弊社バルテックのアドベントカレンダーにエントリーしています。
http://www.adventar.org/calendars/414

今回のエントリでは趣向を変えてプログラミングの話をしてみようと思います。
忘年会帰りのsakitaです。

プログラムと言いましても、javaのような高級な言語は使えませんので、主に運用などで使われるシェルプログラムで良く使われるsedやawkを紹介したいと思います。

まずはsed。これは主に文字列変換で使います。

sed -e "s/脂肪/エネルギー/g"

という指定をすると、文字列中の「脂肪」という文言が「エネルギー」という文言に変わります。
ファイルの中身を返還するような場合は、

cat fatboy.txt | sed  -e "s/脂肪/エネルギー/g" > smartboy.txt

とすると、fatboy.txtにある脂肪という文言をエネルギーに変えたテキストがsmartboy.txtに出力されます。

他にも行削除など用途があります。


次にawkです。これ結構いろいろつかえて便利です。
たとえば、こんなファイル。

1      9     18     1
2      9     19     1
....

いわゆる勤怠ファイルです。2列目が出勤時間で3列目が退勤時間で4列目が休憩時間です。
退勤時間だけ出力したい場合、

kintai.txt | awk '{print $3}'

こんなかんじで指定ができます。
計算もできちゃったりします。

たとえば、勤務時間を計算する場合、

kintai,.txt | awk '{print $1 $3-$2-$4}'

こんな感じでうまくいきます。

いろいろ便利そうなのですが、なかなかとっつきづらいかもしれません。
こういうときどうするの? といった疑問があったとき、私が良く見るサイトはこちら。
https://www.usptomo.com/
USP友の会の勉強会スライド。
表計算をしたりソートしたりなどなど、自由自在に1行プログラムで文字列操作をしています。

私もさらに勉強をしてawk使い見習いくらいになりたいものです。

2014年12月18日木曜日

オラクルマスターあれこれ

今回の記事は、弊社バルテックのアドベントカレンダーにエントリーしています。
http://www.adventar.org/calendars/414

オラクルマスターというと、大抵はORACLE MASTER Oracle Databaseを指していると思います。
ただ、Oracle社は買収によってMySQLやJavaなどを手に入れていますので、オラクルマスターは様々な種類がありますので、
今日はオラクルマスターについて紹介をしていきたいと思います。

まずはORACLE MASTER Oracle Databaseから。
資格の種類はBronze、Silver、Gold、Plutinumとありますが、この呼称は日本のみの呼び名だというのはご存知でしょうか?
日本以外では、Oracle Certification Associate(OCA)、Oracle Certification Professional(OCP)、Oracle Certification Master(OCM)となっています。
一つ足りないと思われるかも知れませんが、Bronzeは日本のみの資格となっています。Silverを取るとOCA、Goldを取るとOCPに自動認定されます。
ただし、Silver、Goldなどが認定されるのは日本語で受験した場合となります。英語で受験をした場合はOCA、OCPなどとなりますのでご注意ください(敢えて英語で受ける人は少ないと思いますが)。
続いて、Expertについてですが、これはGoldなどの枠とは別となります。
現在、Database関連ではパフォーマン2014年12月15日~ 2015年5月31スチューニング、RAC、Linuxは参考書が売られているので比較的取得者が多いのではと思います。Linuxは前提資格としてSilver、パフォーマンスチューニングとRACはGoldが前提資格となっています。
中には前提資格なしで認定されるExpertもあります。Implemention、Data Warehouseがありますが、いずれも英語のみの試験です。
毛色は違いますが、PL/SQLもSilverとGoldがあります。ExpertはSQLとSQL Tuningがありますが、こちらも英語のみです。

ORACLE MASTERで最近注目と言えば、Javaではないでしょうか。
Java ProgrammingもBronze、Silver、Goldがあります。参考書も出てきましたね。
他にはOracle LinuxやOracle SolarisといったOSの資格、Exadataなどのエンジニアドシステム、Oracle VMなどの仮想化、E-Business suiteのようなアプリケーションに関するものなど、資格の数は100はあるのではないでしょうか。
これらの資格は参考書が無いものがほとんどなので、取得は大変だと思いますが、そのぶん希少価値はありますので取得すると評価が高まるかもしれません。


最後に、最近のORACLE MASTERの動きについて2つ。
・Recertification(再認定)ポリシーの導入
11月1日より、Oracleのデータベース資格に関して再認定ポリシーが導入されました。
これは他の多くのIT資格と同様、新バージョンに向けて資格を取得していかないと認定者として認めないというものです。
今後は資格終了日から1年以内にアップグレードをしないと、資格認定者とならなくなります。
現在、既にOracle Database 9i以下の資格は終了しており、2015年10月までにアップグレードしないと有効な認定者として認められなくなりました。10gについても2015年2月に終了し、2016年2月を過ぎると有効な認定者となりません。
アップグレードをするのは大変ですが、一方で朗報でもあると思っています。
といいますのは、9iまでは現在のSilver相当をGold、現在のGold相当をPlutinumと呼んでいたため、9i Plutinum取得者と聞くと優秀な技術者に聞こえてしまうので、こういったことが排除されるのは良い傾向かなと思っています。
会社には受験料で迷惑かけることになってしまいますが・・・。

参考資料はこちら
https://blogs.oracle.com/oraclemaster/entry/recertification_policy

・一回目が不合格でももう一度挑戦できるチャンス!
2014年12月15日から2015年5月31日の間、Oracle Database 12c試験、Java試験の一部で1回目の試験が不合格となった場合、同じ試験を期間中に受けた場合2回目が無料になるキャンペーンをやっています。
これを機にOracle Database 12cへのアップグレードに挑戦してみては如何でしょうか?

参考資料はこちら
http://www.oracle.com/jp/education/index-172250-ja.html

2014年12月14日日曜日

ダイレクトロードでFORCE LOGGINGしたときのREDO量見積もり

今回の記事は、弊社バルテックのアドベントカレンダーにエントリーしています。
http://www.adventar.org/calendars/414


ダイレクトパスインサートとは、バッファキャッシュを介さずにデータを落とし込む機能ですので、効率的にデータのインサートができます。
この機能を使用する場合、REDO情報の生成を最小限に抑えるNOLOGGINGモードを指定できます。
ただ、DataGuardやGolden Gateなどで遠方のサーバーへのRedo転送をする際、NOLOGGINGのままだとログ適用エラーやデータアクセスエラーが発生してしまうので、
FORCE LOGGINGにする必要があります。

通常の処理で発生したREDOログ量をそのまま転送REDOログ量と見積もって良いのですが、ダイレクトパスインサートの処理が大量にある場合は、FORCE LOGGINGにした分の転送REDOログ量を見積もる必要が出てきます。


このログ量はAWRの表示で見ることができます。

ダイレクトパスインサート分のREDO量 = block_size * redo size for direct writes - redo size for lost write detection
REDOログ量総計 = 通常のREDO量 + ダイレクト分のREDO量

となります。

ダイレクトパスインサート分のREDO量を見積もっていなかったことで転送ラグが出てしまった、ということが以前あったので、事前の見積もりは大事だなと思いました。

2014年12月11日木曜日

機械学習で遊んでみる

今回の記事は、弊社バルテックのアドベントカレンダーにエントリーしています。
http://www.adventar.org/calendars/414


当Blogはデータベース関連ですが、今日はちょっと毛色の違う話をしてみようと思います。
先々月、代休を取ってマイクロソフトカンファレンスに遊びに行ったとき、機械学習についてセッションを聞きました。
クラウドベースのMicrosoft Azure Machine Learning(ML)が6月に発表され、今はプレビュー版が無料で試せます。
http://azure.microsoft.com/en-us/services/machine-learning/

機械学習について、簡単に説明します。
Wikipediaによると、「センサやデータベースなどからある程度の数のサンプルデータ集合を入力して解析を行い、そのデータから有用な規則、ルール、知識表現、判断基準などを抽出し、アルゴリズムを発展させる。」とあります。
以前、米大手スーパーマーケットチェーン・ウォールマートの分析で「おむつを買った人はビールを買う傾向がある」という分析結果が出たという話を聞いたことがある方は多いのではないでしょうか。
現在ではネットショッピングなどでこれを買った人はこんなものも買っていますという表示が出てくるのを見ることができると思います。
(これ、結構当たっていてつい一緒に購入してしまいそうになります)

しかしながら、こうしたアルゴリズムを構築することは難しいですが、それをクラウドサービスとして提供しようというのが、Microsoft Azure Machine Learning(ML)です。
というわけで、実際に試してみました。

まず、ログインするとビデオによる概要説明が始まります。
それを終えると、こんな画面が出てきます。













さて、データを投入しましょう。
今回は過去半年間の飲み記録(平日のみ)を入力し、いつ飲みに行く傾向があるか調べてみようと思います。
どうでもいいデータですね。。。












このCSVデータを入れていきます。入力ファイルはCSVファイルなどのほか、R言語のデータも入れることができるようです。
そして、データ解析が始まります。まずはインプットにさっきのデータをインプット。
次にデータをSplitします。今回は75%とします。なぜデータを分割するかと言いますと、75%のデータの頻出度などを分析し機械学習を実施し、残り25%の結果と合わせて精度を高めるという流れて進みます。
その後、分析対象の列選択(Project Columns)を行い、トレーニング=学習を実施(Train Model)し、残りのSplitした結果と比較していく流れになります。












結果が画面右。会社のラウンジでお酒を飲むのは金曜日という傾向が発見できました。
当人にしてみたら、ごくごく当然の傾向が導き出されました。












もっと多角的に検証できると思うので、徐々に勉強していきたいと思います。

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で。

2014年11月26日水曜日

12.1.0.2 Zone Maps 入門 Part I

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

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

日本語訳:sakita


==========

Zone Mapは、選択した列の最小値と最大値を表の各「ゾーン」に格納することでテーブルのアクセス時にディスクブロックの「プルーニング」を可能にする、インデックスのような構造の新しい機能である。
ゾーンは、単にテーブル内の連続したブロックの範囲です。Zone MapはExadata Storage Indexの概念と似ていますが、明示的に制御し、維持することができる物理的なオブジェクトです。
また、 Bitmap-Join indexesと同様の方法で、Zone Mapで定義されたテーブルの列の属性をキーとして外部結合をすることができます。
Zone Mapは同じく新機能として導入されたAttribute Clusteringの一部として作成することもできます。(前回の記事で書いています)。
興奮してしまいますが、一つ注意が必要です。Zone Mapは残念ながらExadataまたはSuperCluster限定の機能で、Partitioning Optionが必要です。もしそれでもまだご興味がおありでしたら、続きをお読みください。


まずは、BIG_BOWIEテーブルを作成することから始めましょう。この記事ではALBUM_ID列が非常に良くクラスタ化されていることに注目してください。


SQL> create table big_bowie (id number not null, album_id number not null, artist_id number not null, format_id number,
release_date date, total_sales number, description varchar2(100));

Table created.

SQL> create sequence bowie_seq order;

Sequence created.

SQL> create or replace procedure pop_big_bowie as
  begin
    for v_album_id in 1..100 loop
        for v_artist_id in 1..100000 loop
            insert into big_bowie values (bowie_seq.nextval, v_album_id, v_artist_id, ceil(dbms_random.value(0,5)) * 2,
     trunc(sysdate-ceil(dbms_random.value(0,10000))), ceil(dbms_random.value(0,500000)), 'THE RISE AND FALL OF ZIGGY STARDUST AND THE SPIDERS FROM MARS');
        end loop;
          commit;
    end loop;
    commit;
end;
/

Procedure created.

SQL> exec pop_big_bowie

PL/SQL procedure successfully completed.

SQL> exec dbms_stats.gather_table_stats(ownname=>user, tabname=>'BIG_BOWIE', method_opt=>'FOR ALL COLUMNS SIZE 1');




次にALBUM_ID列に通常のB-Treeインデックスを作成します。


SQL> create index dwh_bowie_album_id_i on dwh_bowie(album_id);

Index created.


ALBUM_ID列のなかから、データのちょうど1%を占めている特定の値を探して、次のクエリを実行します。


SQL> select * from big_bowie where album_id=42;

100000 rows selected.

Elapsed: 00:00:00.29

Execution Plan
----------------------------------------------------------
Plan hash value: 1830705794

------------------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name                 | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |                      |   100K|  8984K|  1554   (1)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| BIG_BOWIE            |   100K|  8984K|  1554   (1)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN                  | BIG_BOWIE_ALBUM_ID_I |   100K|       |   201   (2)| 00:00:01 |
------------------------------------------------------------------------------------------------------------


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

   2 - access("ALBUM_ID"=42)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
       1590  consistent gets
          0  physical reads
          0  redo size
    9689464  bytes sent via SQL*Net to client
        760  bytes received via SQL*Net from client
         21  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
     100000  rows processed



CBOは優れたクラスタリングのデータがあるのでインデックスを使用し、consistent getsは1590と比較的低いです(arraysizeは5000で設定されています)。

インデックスをinvisibleにして先ほどのクエリを何度か行います。


SQL> alter index big_bowie_album_id_i invisible;

Index altered.

SQL> select * from big_bowie where album_id=42;

100000 rows selected.

Elapsed: 00:00:00.29

Execution Plan
----------------------------------------------------------
Plan hash value: 469213804

---------------------------------------------------------------------------------------
| Id  | Operation                 | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT          |           |   100K|  8984K|  3269  (12)| 00:00:01 |
|*  1 |  TABLE ACCESS STORAGE FULL| BIG_BOWIE |   100K|  8984K|  3269  (12)| 00:00:01 |
---------------------------------------------------------------------------------------


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

   1 - storage("ALBUM_ID"=42)
       filter("ALBUM_ID"=42)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
     135085  consistent gets
     135068  physical reads
          0  redo size
    3130019  bytes sent via SQL*Net to client
        760  bytes received via SQL*Net from client
         21  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
     100000  rows processed


実行時間はExadata Storage Indexes (SI) と同様、全表スキャン(FTS)であるにもかかわらず、ほとんど同一であることにお気づきでしょう。
データは非常によくクラスタ化された状態で、SIは非常に効果的にアクセスする必要のある物理ブロックを「プルーニング」することができました。
明らかにこれらのクエリのいずれかを実行したセッションのセッション統計を見て確認できます。

SQL> select name , value/1024/1024 MB
from v$statname n,  v$mystat s
where n.statistic# = s.statistic# and
n.name in ('cell physical IO interconnect bytes returned by smart scan', 'cell physical IO bytes saved by storage index');

NAME                                                                     MB
---------------------------------------------------------------- ----------
cell physical IO bytes saved by storage index                    1038.32813
cell physical IO interconnect bytes returned by smart scan       9.56008911


テーブルの大部分は、実際のStorage Indexesの結果として読み飛ばされています。


これから、ALBUM_ID列に基づく基本的なバージョンのZone Mapを作成していきます。


SQL> create materialized zonemap big_bowie_album_id_zm on big_bowie(album_id);

Materialized zonemap created.

Zone Mapはマテリアライズド・ビューと同様に実装され、マテリアライズド・ビューと同様にリフレッシュすることができる独立したテーブル構造です。
これは、Zone Mapのリフレッシュ属性に応じて、Zone Mapと従来のインデックスとの重要な違いであり、DML操作中に更新されない場合があります。
デフォルトのリフレッシュ属性は、DML操作後に「古く」なることを意味する「REFRESH ON LOAD DATA MOVEMENT」です。
Zone Mapは基本的には、表の各「ゾーン」内の対応する列(複数可)の最小値と最大値を格納します。
Zone Mapの内容を見てみると…(下にあるリストの一部をご覧ください)


SQL> select zone_id$, min_1_album_id, max_1_album_id, zone_rows$

from big_bowie_album_id_zm;

       ZONE_ID$ MIN_1_ALBUM_ID MAX_1_ALBUM_ID ZONE_ROWS$
--------------- -------------- -------------- ----------
   385855025152              1              2      66234
   385855029250              5              6      56715
   385855029251              7              7      76562
   385855025155              7              8      76632
   385855004675              8              9      76633
   385855025161             21             22      75615
   385855004684             29             29      75582
   385855004685             31             32      75545
   385855004687             35             36      75617
   385855029267             43             44      75615
   385855029270             50             50      75481
   385855029275             61             62      75616
   385855025179             62             63      75530
   385855029284             81             82      75615
   385855029285             84             84      75480
   385855004710             87             88      75616
   385855004711             90             91      75484
   385855029293            100            100      75799
   385855029254             13             14      75615
   385855029255             16             16      75481
   385855004681             22             22      75480
   385855004682             24             25      75616


...

   385855025184             73             74      75615
   385855004705             76             77      75615
   385855029283             79             80      75615
   385855029286             86             87      75616
   385855029287             88             89      75618
   385855004714             97             97      75771
   385855029295            100            100      15871



134 rows selected.


いくつかの注意点を書きます。
まず、Zone Mapのために保存されるデータの量はごくわずかです。各Zoneには8Mのストレージが対応し、今回はおおよそ75500行です。これはZone Mapと従来のB-Treeインデックスとの重要な違いです。
インデックスのエントリは参照される行ごとに有しますが、Zone MapはテーブルのみのZoneごとに1つのエントリを有します。
また、ALBUM_ID行は非常によくクラスタ化されているので、同じZone内ではALBUM_IDの値が非常に狭い範囲の最小値/最大値になっています。これは、Zone MapによってOracleは非常に簡単に興味のあるデータを含む大多数のZoneからのストレージのアクセスを「プルーニング」することにおいて極めて有効であることを意味します。

このZone Mapがいかに小さいか確認しましょう。


SQL> select segment_name, segment_type, bytes from dba_segments where segment_name like 'BIG_BOWIE%';

SEGMENT_NAME              SEGMENT_TYPE     BLOCKS      BYTES
------------------------- ------------ ---------- ----------
BIG_BOWIE                 TABLE            139264 1140850688
BIG_BOWIE_ALBUM_ID_I      INDEX             20480  167772160
BIG_BOWIE_ALBUM_ID_ZM     TABLE                 8      65536


テーブルやインデックスがはるかに大きいのに対し、Zone Mapは64Kのエクステント1つしか必要ではありません。事実、実際に134行はすべて8Kのデータブロックに収めることができます!
2つの新しいデータ・ディクショナリビューは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の現在の状態がDBA_ZONEMAPSで見ることができます。


SQL> select measure, position_in_select, agg_function, agg_column_name
from dba_zonemap_measures where zonemap_name='BIG_BOWIE_ALBUM_ID_ZM';

MEASURE                        POSITION_IN_SELECT AGG_FUNCTION  AGG_COLUMN_NAME
------------------------------ ------------------ ------------- ---------------
"BOWIE"."BIG_BOWIE"."ALBUM_ID"                  3 MAX           MAX_1_ALBUM_ID
"BOWIE"."BIG_BOWIE"."ALBUM_ID"                  2 MIN           MIN_1_ALBUM_ID


さらに、Zone Map内の列の詳細はDBA_ZONEMAP_MEASURESで見ることができます。

BIG_BOWIEテーブルで同じクエリを再実行してみましょう。


SQL> select * from big_bowie where album_id=42;

100000 rows selected.

Elapsed: 00:00:00.28

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
2364  consistent gets
0  physical reads
0  redo size
3130019  bytes sent via SQL*Net to client
760  bytes received via SQL*Net from client
21  SQL*Net roundtrips to/from client
0  sorts (memory)
0  sorts (disk)
100000  rows processed

CBOはFTS(TABLE ACCESS STORAGE FULL WITH ZONEMAPとfilter predicate informationを見てください)中にZone Mapを使用しています。
consistent getsではデータベースのインデックスを介した場合と比較して増加(2364 vs 1590)しますが、139000近くの奇数のブロックがどこにも無いので前回に匹敵する性能であり、そんなに悪くはありません。
増えたconsistent getsはZone全体が読み取られる必要があるため必要であり、一方、B-Treeインデックスは対象のデータが含まれている特定のZoneのみ指定することができます。

従ってZone Mapは「十分に良い」結果をもたらしました。
一方、データベースまたはExadata Storage Serverのいずれかをバウンスしたあとであっても、
Zone Mapを維持する方法を制御することができ(後述します)、Zone Mapオブジェクトが常に存在することを保証する非常に最小限のストレージを必要としています。

PartIIでは、ベーステーブル上のいくつかのDMLを実行するときに何が起こるか見てみましょう。

2014年11月15日土曜日

db tech showcase 2014 東京に参加しました。

年に2回のデータベースの祭典、db tech showcaseに参加してきました。

毎年春に大阪、秋に東京で開催され、セールストーク一切無し、Oracle Aceをはじめとした多くのトップ技術者のセッションを聞ける貴重な機会です。初回開催から欠かさず参加し、今回は初日と二日目に参加しました。
今回、Oracleのセッションでは多くの海外からのスピーカーが来ました。
OracleのパフォーマンスチューニングではCraig Shallahamarさん、AskTomで有名なTom Kyteさん、
新たにPythian Asia Pasificの代表に就任されたバックアップリカバリのプロフェッショナルFrancisco Alvarezさんなど
蒼蒼たるメンバーです。

聴講したセッションは以下の通りです(敬称略)。

11/11
Memory Structure Control: How it works (latches & mutexes) Craig Shallahamer
About server sizing and implementing Hard Partitioning technologies to stop over-licensing Bjoern Rost
Everyone talks about DR / But why so few implement it Francisco Munos Alvarez
Improving the performance of PL/SQL function calls from SQL Tim Hall
Scalability with MariaDB and MaxScale Colin Charles
[7-eleven] DR with Physical Replication Technology (+DEMO) Anton Els/大橋美幸
[DoBoken] 月間10億PVから学んだMongoDBアンチパターン 磯部有司

11/12
Oracle Optimizer: What’s new in Oracle Database 12c? Tom Kyte
Hitchhiker’s Guide to Oracle Database Upgrades Mike Dietrich
Why Engineered System? Tom Kyte
Multitenant in the Real World Mike Dietrich
Introduction to Time-Based Performance Analysis: Stop the guessing! Craig Shallahamer
PostgreSQLを拡張してみよう 高塚遥
Oracle 12c Backup & Recovery / What is new? Francisco Munos Alvarez

Craigさんのセッションは初日の一コマ目。LatchとMutexの内部構造についての講義でした。
こちらがボディランゲンジを交えてわかりやすく、大変勉強になりました。
2日目のセッションも、AWRの分析手法について丁寧に解説してくださり、大収穫でした。

また、TomasKyteさんのWhy Engineered SystemではExadataの機能紹介があり、
よくわかっていなかったHybrid Columnar Compressionについて勉強になりました。

12.1.0.2から、Exadataの新機能としてZone Mapというのができたと、Kyteさんから紹介がありました。
こちらを併用することで、SmartScanによるストレージでの絞り込み率を上げることに効果があるのだそうです。
また、Twitterを介して別の方からAttribute Clusteringという機能も有用であるとの紹介がありました。

簡単に調べた内容を紹介します。
・Attribute Clustering
ユーザが指定したカラムの順に物理的にソートされることで、隣接したカラムに内容の近いデータが並び、
ストレージでの絞り込みに効果を発揮できる機能。複数表でもOKとのこと。
データをAPPENDヒントで挿入するか、もしくは表のmove操作も可能。
こちらは非Exadataでも使用できるので、また機会を見て検証したいところです。
・Zone Map
StorageIndexでは1Mごとの単位で、しかも頭8桁での値の最大値/最小値のデータが抽出されますが、
ZoneMapではcreate materialized zonemapを作成することで、カラムの特性に合った単位で抽出ができ、
操作できるようになるというものです。
これは期待大です。検証したいですが、環境を整えるのが難しそうですが…。

これらの内容について、以下のサイトで概要が書かれていますので、興味のある方は見てみてください。
http://www.oracle.com/webfolder/technetwork/jp/ondemand/od12c-aug2014/14-DB12102-coretech-DWH-v1.pdf


様々な学びを得られ、懇親会ではOracleAceの方々ともお話ができ、有意義な参加となりました。

2014年10月29日水曜日

【セミナー】Oracle Days Tokyoに行ってきました

10月22、23日に恵比寿のウェスティンホテルで開催された、Oracle Days Tokyo 2014に行ってきました。
私は10月22日に夜勤明けで行ったので、結局基調講演のみの参加となりました。

普段は足を踏み入れることのない高級ホテルでの開催!

基調講演は、9月にサンフランシスコで開催されたOracle Open Worldの話が中心でした。

いくつか新しい発表があったのですが、特に興味を持ったのがZero Data Loss Recovery Applianceでした。
DBAとして、バックアップリカバリでいかにデータを復旧させることができるかということには日ごろから気にしていますが、最後のバックアップ(アーカイブログを取っていたとしても)以降のデータを消失するリスクは常にあるので、どうやって実現しているのか興味がありました。
常にREDOを送信し続けるとのことでしたが、どんなものなのか調べてみたいと思いました。

もうひとつ、Oracle Big Data SQLもおもしろそうでした。
HadoopのデータをSmart Scanで効率よくデータを持ってこれるようで、Hadoopのデータ操作については大きく流れが変わりそうですね。

夜勤明けのため睡魔との闘いでしたが、新しいことを見聞きできて有意義なひと時でした。

2014年10月12日日曜日

SQL長時間化調査の際にはDBMS_XPLAN.DISPLAY_CURSORを使おう

SQLの長時間化が発生した時に、SQLの実行計画を確認すると思いますが、その際に確認する方法としてexplain planがありますが、
explain planはSQLの実行時と同一環境でないとならないため、必ずしも正確でないことがあります。
また、Oracleのマニュアルでは、「一般にバインド変数では、EXPLAIN PLANが実際の実行計画を表していない場合があります」とあります。
※最近、explain planでSQL実行計画を調査し、失敗してしまったことがありました。

そんなときに確認したいのが、v$sql_planです。
v$sql_planは共有プール内の実行計画情報ですので、同一環境をセットアップする必要がありません。
また、10gからは便利なプロシージャが用意されています。
DBMS_XPLAN.DISPLAY_CURSOR


DBMS_XPLAN.DISPLAY_CURSOR(
   sql_id           IN  VARCHAR2  DEFAULT  NULL,
   cursor_child_no  IN  NUMBER    DEFAULT  0,
   format           IN  VARCHAR2  DEFAULT  'TYPICAL');

例)
SQL ID 'abcdefghijk'に関連付けられたすべての子の実行計画を表示する
SELECT * FROM table (DBMS_XPLAN.DISPLAY_CURSOR('abcdefghijk'));

SQL ID 'abcdefghijk'に指定されているカーソルに対するランタイム統計を表示する
SELECT * FROM table (DBMS_XPLAN.DISPLAY_CURSOR('abcdefghijk', NULL, 'ALLSTATS LAST');

2014年9月10日水曜日

v$sqlによるオフロードの情報取得

以前AWRでどれだけsmart scanによるセルサーバ(ストレージ)への処理オフロードでIOを絞ることができたかを書かせていただきましたが、
SQL単位で確認する方法を調べてみました。

Exadataでは、v$sqlで以下のカラムが追加となっています。

IO_CELL_OFFLOAD_ELIGIBLE_BYTES : セルサーバ(ストレージ)でフィルタリングが可能なバイト数
IO_CELL_UNCOMPRESSED_BYTES   : セルサーバ(ストレージ)にオフロードされる非圧縮バイト数
IO_CELL_OFFLOAD_RETURNED_BYTES : セルサーバ(ストレージ)よりオフロードされたバイト数

まず、IO_CELL_OFFLOAD_ELIGIBLE_BYTESがゼロの場合は、セルサーバよりオフロードされません。
IO_CELL_OFFLOAD_ELIGIBLE_BYTESがゼロでないとき、
IO_INTERCONNECT_BYTESに実際のやりとりされたバイト数が出てくるので、この値がIO_CELL_OFFLOAD_ELIGIBLE_BYTESより小さいほどsmart scanが効いていることになります。
また、IO_CELL_UNCOMPRESSED_BYTESではHCCによる圧縮を解凍したバイト数が表示されますので、PHYSICAL READに対して桁が大きいような場合はHCCが効いていることになります。

2014年8月25日月曜日

Storage Indexのダンプを取ってみた

Exadataでは、セルサーバ(ストレージ)側でデータを絞り込んでからDBサーバに転送するSmart Scanという機能がありますが、絞り込むために、セルサーバにはStorage Indexがあり、デフォルトで1MB単位のブロックごとに最大値と最小値、NULLの有無が書き込まれています。

AWRレポートでは、Storage Indexによる絞り込み量のメトリックとして、
cell physical IO bytes saved by storage index

があります。

しかしながら、この間の検証でこの値が一向に0のままなので調べてみると、複数DBが相乗りしているサーバの場合、1DBのみしかこのメトリックが使えないようです。

ならば、どうやってStorage Indexが効いているのか調べれば良いでしょうか?
その答えは、Storage Indexのダンプにありました。

まず、隠しパラメータでcell serverのtraceファイルが出力されるように設定します。
SQL> alter session set "_kcfis_storageidx_diag_mode"=2;

そして、SQLを実行してStorage Indexの使われ方を調べてみます。
SQL> select col1,col2,col3,col4,col5 from table1 where col1 > '000000010000000';
ちなみに、col1はchar(15)です。

さて、Storage Indexのdumpを取ってみます。
CELLCLI> alter cell events="immediate cellsrv.cellsrv_storidx('dumpidx',all,AAAAA,B,CCCCC)";

AAAAA : data_object_id  (select data_object_id from dba_objects)
B    : tablespace    (select ts# from ts$)
CCCCC: ksqdngunid   (select ksqdngunid from x$ksqdn)

これで、ダンプが取れるはず。。。

※一部、Xにしています。
2014-08-25 15:25:14.127639*: RIDX (XXXXXXXXXXXXXX) : st 2 validBitMap 0 tabn 0 id {AAAAA B CCCCC}
2014-08-25 15:25:14.127639*: RIDX: strt XX end XXXX offset XXXXXXXXXX size XXXXXXX rgnIdx XXXX RgnOffset XXXXX scn: 0x0000.000fbc02 hist: 0x49
2014-08-25 15:25:14.127639*: RIDX validation history: 0:PartialRead 1:PartialRead 2:PartialRead 3:Undef 4:Undef 5:Undef 6:Undef 7:Undef 8:Undef 9:Undef
2014-08-25 15:25:14.127639*: Col id [1] numFilt 4 flg 2:
2014-08-25 15:25:14.127639*: lo: 30 30 30 30 30 30 30 34
2014-08-25 15:25:14.127639*: hi: 30 30 30 30 30 30 30 34

1行目のid {AAAAA B CCCCC}が、それぞれdata_object_id、tablespace、ksqdngunidに相当します。
Col id [1]の1は、dba_tab_columnsの値と一致します。
そして、loは最小値、hiは最大値となります。

あれ・・・StorageIndexは8桁しかない。
実は、StorageIndexは左から8桁分しかデータが入らないようです。従って、カラムの値によっては似たような値が入ることで、StorageIndexの効きが悪くなることもあるようです。

StorageIndex、奥が深いです。

2014年8月2日土曜日

Oracle In-memory Optionのメモ書き

Oracle 12.1.0.2からIn-memory Optionが出たので、かなり話題になっていますね。
まだ検証できていませんが、マニュアル、ネットで拾ってきた情報をメモ書きしてみます。


■どうやってIn-memory Optionにするのか
・12.1.0.2にバージョンを上げる
・compatibleを12.1.0.2にする
ALTER SYSTEM SET compatible='12.1.0.2.0' scope=spfile;
・Inmemoryに使うサイズを設定(デフォルトで0)
ALTER SYSTEM SET inmemory_size=1G scope=spfile;
※100MB以上に設定する必要がある
・Inmemory queryはENABLEにする(デフォルトでENABLEになっている)
ALTER SYSTEM SET inmemory_query=ENABLE;

これらは静的パラメータですので、再起動が必要です。


・テーブルの設定
ALTER table table1 inmemory;

dba_tables表などに、INMEMORYカラムができていますので、DISABLEかENABLEかを確認できるようです。

・実行プラン
インメモリが使われている場合は、TABLE ACCESS INMEMORY FULL

・In-memory Areaに乗っているか確認できるV$表
SELECT segment_name, inmemory_size, bytes FROM V$IM_SEGMENTS;


ただ、Update後やIndex作成後はIn-memory Areaに乗らないことがあるらしいので、
この件を中心に検証を進めていこうと思います(妻子が実家に行っている間に・・・)

2014年7月19日土曜日

セルサーバのアラートログ

セルサーバのアラートログ

OracleではDBインスタンスのアラートログ、RACの場合はASMインスタンスのアラートログが用意されていますが、
セルサーバにもアラートログが用意されています。

/opt/oracle/cell11.2.3.2.1_LINUX.X64_130109/log/diag/asm/cell/`hostname`/trace
alert.log
にあります。
※cell11.2.3.2.1_LINUX.X64_130109はバージョンによって変わります。


/opt/oracle/cell11.2.3.2.1_LINUX.X64_130109
は、ログとかプログラムとかがいろいろ入っていたりします。

/opt/oracle/cell11.2.3.2.1_LINUX.X64_130109/cellsrv/bin
には、cellcliも入っています。


ちなみに、アラートはcellcliからも見ることができるようです。
cellcli
CELLCLI> list alerthistory
where句で条件を絞ったりもできます。
CELLCLI> listalerthistory where severity = 'critical'

2014年7月9日水曜日

セルサーバのコマンドラインcellcli

Exadataでは、DBキャッシュのほかにセルサーバにもキャッシュを持っています。
セルキャッシュは、オブジェクトに対して、NONE,DEFAULT,KEEPのいづれかを選択できます。
 alter table table1 storage (cell_flash_cache keep);

ところで、実際にセルサーバの中ではどのように処理されているのでしょうか?
セルサーバにはcellcliという機能が用意されています。
コマンドの一覧はhelpで見ることができます。

CellCLI> help

 HELP [topic]
   Available Topics:
        ALTER
        ALTER ALERTHISTORY
        ALTER CELL
        ALTER CELLDISK
        ALTER GRIDDISK
        ALTER IORMPLAN
        ALTER LUN
        ALTER THRESHOLD
        ASSIGN KEY
        CALIBRATE
        CREATE
        CREATE CELL
        CREATE CELLDISK
        CREATE FLASHCACHE
        CREATE GRIDDISK
        CREATE KEY
        CREATE THRESHOLD
        DESCRIBE
        DROP
        DROP ALERTHISTORY
        DROP CELL
        DROP CELLDISK
        DROP FLASHCACHE
        DROP GRIDDISK
        DROP THRESHOLD
        EXPORT CELLDISK
        IMPORT CELLDISK
        LIST
        LIST ACTIVEREQUEST
        LIST ALERTDEFINITION
        LIST ALERTHISTORY
        LIST CELL
        LIST CELLDISK
        LIST FLASHCACHE
        LIST FLASHCACHECONTENT
        LIST GRIDDISK
        LIST IORMPLAN
        LIST KEY
        LIST LUN
        LIST METRICCURRENT
        LIST METRICDEFINITION
        LIST METRICHISTORY
        LIST PHYSICALDISK
        LIST THRESHOLD
        SET
        SPOOL
        START


特定のオブジェクトがキャッシュされているかどうかを確認することもできます。
まずは、DBにログインし、確認対象のオブジェクトのdata_object_idを確認します。
SQL> SELECT data_object_id FROM dba_objects WHERE object_name=‘EMP’;

その後、Storageにログインし、確認したdata_object_idから検索すると、キャッシュされているフラッシュキャッシュを見ることができます。
CellCLI> list flashcachecontent where objectNumber = data_object_id detail


これでセルキャッシュに乗っているか確認ができます。
ちなみに、セルキャッシュをキャッシュするには、以下の2つのコマンドが必要になります。

CellCLI> alter flashcache all flush ←キャッシュをフラッシュし、以後キャッシュしない
CellCLI> alter flashcache all cancel flush ←キャッシュのフラッシュをキャンセルする(以後キャッシュできるようになる)

2014年6月21日土曜日

【セミナー】db tech showcase 2014 大阪 に行ってきました

6/19、20でdb tech showcase 2014 大阪に行ってきました。
http://www.insight-tec.com/dbts-osaka-2014.html


データベース関連のセミナーとしては日本最大規模のもので、1回目(Insight Out)から欠かさず参加しています。このイベントのお陰でデータベースをもっと勉強したいと思うようになったきっかけなので、これからもできるだけ参加したいと思っています。

6月19日、朝イチの新幹線で大阪に向かいました。


朝9時に大阪到着。新幹線は速いです。


この日は以下のセッションを聞きました。

C21:DBAが知っておくべきハードウェアテクノロジー
A22:OracleからOSS-DBへ乗り換える前にSE Oneを有効活用しよう
B23:PostgreSQLのインデックス・チューニング
A24:SQL Server パフォーマンス問題対処 Deep Dive
C25:日本のビッグデータを誰が必要としているのか
A26:温故知新 データベース☆オールスターズ

興味のあるところをごたまぜで聞いてみました。特にハードウェアとDBについては勉強していきたいと思いつつもどう取り組んでいこうかと悩んでいたことので、とても役に立ちました。

この日は大阪に宿泊、夕飯は新世界に近いジャンジャン横丁で串カツを食べました。



6月20日、ワールドカップで盛り上がりましたが、また午前のセッションから聞きに行きました。

B31:LOGMinerってレプリケーションソフトで使われているけどどうなってる?
C32:第四世代 SQL Server 最新機能とインテル Xeon E7 v2 検証結果 Part1
C33:第四世代 SQL Server 最新機能とインテル Xeon E7 v2 検証結果 Part2
A34:HDDからインメモリーテクノジーへ
C35:HadoopはRDBエンジニアに何を求め、どうなろうとしているのか

最後の村上さんのセッションも聞きたかったのですが、残念ながら帰りの新幹線の関係で聞けませんでした。
特にSQLServerのアーキテクチャの変更点は勉強になりました。AWE選択できないんですね。

今回も面白いセッションをたくさん聞かせてもらいました。秋には東京で行われるので、また行きたいですね。

2014年6月7日土曜日

ORA-00020: maximum number of processes

先週は金曜日にOracleのパフォーマンスチューニングネタで自社の社内セミナー講師をさせてもらい、土曜日にPostgresしくみ勉強会に参加させてもらいました。
仕事で忙しくてなかなか勉強する時間がとれませんが、だいぶ落ち着いてきたのでいろいろとインプットしていきたいなと思っています。

さて、今週はRealApplicationTesting(RAT)による検証で、こんなOracleエラーに遭遇したお話を。

ORA-00020: maximum number of processes(1000)

起動している初期化パラメータPROCESSの上限を超えてしまったエラーでした。
RATで設定していたセッションが初期化パラメータを超えていたために発生させてしまいました。


対処としては、プロセス数を上げればOKです。

alter system set processes = 4000 scope = both;

ただ、OS側でプロセスを増やしてよい設定になっているか検討は必要です。
システムリソースの上限を設定するulimitで確認する必要があります。

ulimit -aでリソース上限の設定を確認できます。

processes : プロセス数上限
memory    : 使用されるメモリーの上限

ここらへんは見ておいたほうがよいかも。


ulimit -nで設定変更できますが、再起動すると設定が戻ってしまうので、limit.confの設定も変更する必要があります。

2014年5月24日土曜日

ASMストレージ設定とリバランス

OracleではストレージをASM(Automatic Storage Management)ディスクとして使用することが多いですが、
ASMでは、冗長性を保持してデータを持つことができます。ASMミラーですね。

冗長性レベルは3段階あります。
EXTERNAL 冗長なし…ストレージ機能で冗長性を担保
NORMAL  2重化
HIGH   3重化


ストレージを分割してディスク設定をすることができますが、同じストレージ内に2つデータを保持してしまうと、そのディスクが故障したときにデータをすべて失ってしまうので、気をつける必要があります。
そこで、ディスクグループ内で障害グループというものを設定します。
たとえば、NORMALの場合は障害グループを2つ以上用意する必要があり、それぞれの障害グループに対してディスクを割り当てます。



・SQL例
以下は、DISKAとDISKBを4つずつにわけて、障害グループを設定してディスクグループを作成する例です

CREATE DISKGROUP dgroup1 NORMAL REDUNDANCY
FAILGROUP controller1 DISK
'/devices/diska1' NAME diska1,
'/devices/diska2' NAME diska2,
'/devices/diska3' NAME diska3,
'/devices/diska4' NAME diska4
FAILGROUP controller2 DISK
'/devices/diskb1' NAME diskb1,
'/devices/diskb2' NAME diskb2,
'/devices/diskb3' NAME diskb3,
'/devices/diskb4' NAME diskb4
<Oracle Databaseストレージ管理者ガイドより>


ディスクが故障すると、ASMはリバランスで均等にデータを他のディスクに割分けてくれます。
ただ、ディスクが故障してもすぐ交換できるなら、リバランスでディスクに負荷がかかって欲しくないという事情もあります。
そこで、リバランスが発生するまでの猶予時間はデフォルトは3.6Hで設定されています。
変更したい場合は以下のコマンドを使用します。
ALTER DISKGROUP data SET ATTRIBUTE 'disk_repair_time' = '4.5h'

また、リバランスにはパラレル化の指定ができます。
ALTER DISKGROUP dgroup1 ADD DISK
      '/devices/diska*'
       REBALANCE POWER 5 WAIT;
<Oracle Databaseストレージ管理者ガイドより>

2014年5月10日土曜日

Smart ScanとStorage Index

Smart ScanとStorage Index

ExadataのSmart Scanでは、データをストレージ側で絞り込んでからDBサーバ側に送ることで、
ストレージのIOを減らすことができ、速く処理することができます。

では、どうやってストレージ側で絞り込みを行うのでしょうか?


Smart Scanによる絞り込みには、Storage Indexを使用します。
Storage Indexは、テーブルの各カラムごと、Regionと呼ばれるデータの区分けごとに
値の最低値と最高値、Nullの有無のデータを格納します。これは自動的に行われるもので、値を制御できるものではありません。

ランダムにデータが入っている場合、多くのRegionを見にいってデータを取って行きますが、
シーケンシャルにデータが入っている場合は、Regionを見に行く回数が少なくて済みます。
これらを念頭にチューニングする必要がありそうです。


AWRレポートでは、Smart Scan関連の2つのメトリックが確認できます。
Cell physical IO bytes saved by storage index
 -Storage Indexによって絞り込まれたIOバイト数
Cell physical IO interconnect bytes returned by smart scan
 -Smart Scanで返されたIOバイト数

上のメトリックと下のメトリックの値がかい離している場合は、storage indexが有効でないことが言えると思います。



ちなみに、Storage Indexを使用しないようにすることもできます。
_kcfis_storageidx_disabled という隠しパラメータを使用します。デフォルトはFalse(使用不可にしない)です。

 alter session set "_kcfis_storageidx_disabled"=true;

2014年4月27日日曜日

SmartScanの検証


最近、業務でExadataを触っておりますが、Exadataの特徴の一つとしてSmartScanがあります。
通常、データベース側でSQL文を発行すると、ストレージからデータを取ってきて、データベースで必要な情報を抽出してSQLを実行します。
これをExadataでは、ストレージ側でデータベースに渡すデータをあらかじめ抽出することによって物理I/Oを減らす機能です。
SmartScanを有効にするには、Direct Path Readである必要があります。
実行計画でDirect Path Readを選択してくれないと、Smart Scanが効かないのが問題となる可能性があります。
一応、こんな方法でSmartScanを効かすことはできます。
alter session set "_serial_direct_read"=true;

とはいえ、アプリ側でalter文を発行するのも嫌、というのはあると思いますので、もう少し調べてみました。
すると、こんな隠しパラメータを見つけました。
_small_table_threshold
11.2からは、セグメントサイズが 5×_small_table_threshold×blocksize以上の場合、Direct Path Readを選択するようです。
ちなみに、_small_table_thresholdはデフォルトではバッファキャッシュの2%になるような値にセットされるようです。
つまり、バッファキャッシュを大きくすればするほど、DirectPathReadは効きづらくなるということのようです。

ただ、セグメントサイズ > 5×_small_table_threshold×blocksizeの場合であっても、SmartScanにならない事象が発生してしまいました。
これについては、OracleACEの渡部さんが、TanelPoderさんのブログを翻訳してくださっています(素晴らしい!)。
http://www.csus4.net/d/japanese_translations_of_tanel_poder_s_posts_and_articles/optimizer-statistics-driven-direct-path-read-decision-for-full-table-scans-_direct_read_decision_statistics_driven-ja/

11.2.0.2から少し事情が違うようです。
もう少し検証が必要そうです。

2014年4月23日水曜日

[受験記] データベーススペシャリスト試験

この間の日曜日は情報処理技術者試験ということで、私はデータベーススペシャリスト試験を受けてきましたので、雑感というかレポートを書きます。

昨年の秋試験で一部試験免除の権利を取得したので、午前2からの試験でした。
[午前2]
例年通り過去問からの出題も多いが、やや用語を答えさせる問題が増えた感があり、少し焦りました。
[午後1]
傾向が大きく変わりました。
例年はデータベース基礎理論、テーブル設計、SQLの3問中2問を選択するものでしたが、
今年はデータベース基礎理論、データベース同時実行制御、テーブル設計+SQLの3問となり、必ずSQLの問題は解かなければならなくなりました。
同時実行制御の問題は苦手なので、問2は避けて問1、問3を選択。
データベース基礎理論はやや難しく45分かかってしまったが、テーブル設計+SQLは30分程度で回答できました。
[午後2]
例年は解答用紙が冊子であるが、今年は一枚紙なので焦ったが、傾向は例年通り。
問2のE-R図を選択。設問3の(2)bに10分程度解答に時間がかかったものの、消去法で解答を導き出した。ひとまずすべて書き込むことができました。
今年で5回目の受験なので、そろそろ合格したいですね。

2014年4月13日日曜日

データベースリプレイの基礎知識

先週から現場でRealApplicationTesting(RAT)を使用した性能チェックの準備を始めています。
データベースリプレイは、システム変更の影響を分析する機能です。
リプレイまでの流れは以下の通り
 ・本番システムでワークロードを取得する
 ・取得ファイルをテストシステムにコピーして事前処理する
 ・ワークロードをリプレイする
 ・分析する
ワークロードの取得については、10g以降でサポートされていますが、今回は9iからの変更ですので
サポート問い合わせをしたようです。

テストシステムへの事前処理は、PROCESS_CAPTUREプロシージャを使用します。
BEGIN
 DBMS_WORKLOAD_REPLAY.PROCESS_CAPTURE (capture_dir => 'old_system');
END;
/
ディレクトリのオブジェクトはあらかじめ作っておく必要があります。

準備ができたらワークロードをリプレイします。
まずはテストシステムにデータベースをリストアして、オプションの設定をします。
 synchronization     コミット順序の保持
 connect_time_scale    ワークロード開始から各セッションが接続するまでの待ち時間を縮小できます。
              デフォルトを100とし、待ち時間を半分にしたければ50、などとします。
 think_time_auto_correct セッションがSQL等を実行し終えてから次を実行するまでの思考時間を縮小できます。
              デフォルトを100とし、待ち時間を半分にしたければ50、などとします。
リプレイクライアントには、wrcの設定をします。
 wrc user/password@server mode=replay replaydir=XXXX
これであとは実行です。

今回は構築をほとんどやらなかったのですが、機会があればやってみたいですね。

2014年4月6日日曜日

Exadataの待機イベント

最近、仕事でExadataを触ることが多くなりました。
Exadataとは、Oracle社が出しているストレージ一体型でして、ストレージの部分をセルサーバと言います。
Exadataではsmart scanという、ストレージからの読み込みを先読みして速くする機能があります。
んなもので、いろいろとselectして見てみました。

FULL SCANをしてみて、AWR Reortを見てみると・・
cell multiblock physical read
が出てきました。初めて見る待機イベントです。Exadata以外で言うところのdb file scattered readで、ランダムアクセス。
では、INDEX SCANでは・・・?
cell single block physical read
となります。
smart scanになっているわけではないようです。

smart scanになるには、direct path readにならなければなりません(他にも条件はありますが)。
大きなテーブルを作成してFULL SCANしてみると、
cell smart table scan
smart scanになりました!
ちなみに、INDEX SCANのsmart scan版は cell smart index scanです。

ここらへんを来週ももう少し見ていきたいですね。

2014年3月29日土曜日

AWRのインストールスクリプト

AWR(Automatic Workload Repository)はデータベースのインストールをする際に自動的にインストールがされるので、Statspackのようにインストールスクリプトを流したりという必要はないのですが、
AWRスナップショットを打とうとしたときに、エラーが出て打てません(ORA-06550)。
なので、再インストールしてみました。

--AWR(Automatic Workload Repository)
 Oracleの稼働統計とワークロード情報のスナップショットを自動的に収集/管理する機能。


AWRのインストールには2つのスクリプトがあります。
@/rdbms/admin/catawr.sql    データディクショナリの作成
@/rdbms/admin/dbmsawr.sql  dbms_workload_repositoryパッケージの作成

今回はdbmsawr.sqlを流してみました。
スクリプト自体はちゃんと動きました。
が、現象は変わらずでした。何かいい方法はないだろうか。。

2014年3月21日金曜日

skgm

初めての投稿になります。sakitaです。

このあいだのこと。
検証のためにoracleのSGAを増やそうと、初期化パラメータを変更して再起動をしてみたのですが、startupをしても起動しないということがありました。
SGAを上げすぎたかなと設定を戻して再度startupをしてみたものの、結果は変わらず。。

プロセスは上がっていないし、
OSのディスク容量がひっ迫はしていたものの、整理しても状況変わらず。

かなり悩みましたが、トレースファイルが出ているのを確認してみてみると・・・

skgm error 27126: errno = 12, info = 1, 0, 0, 0
skgm error 27126: errno = 12, info = 1, 0, 0, 0
と延々と出ていました。

skgmはなんじゃらほい、と調べてみたら、
System Kernel Generic Memoryとのことでした。割とレアなエラーのようです。
つまり、システムのカーネルでメモリの獲得に失敗したとのことです。つまりメモリが足りていない。

glanceでメモリ状況をよくよく見てみると、メモリ使用率がすでに93%になっていました。Oracleは上がっていないもののメモリは確保したままなので、再度上げようとしてもメモリが足りないということでした。

確保されたメモリを解放させるのは難しく、結局、OS再起動で復旧しました。

ちなみに、skgpというのもあって、こちらはプロセス関連です。