So-net無料ブログ作成
前の10件 | -

DB技術者として伝えるべき技術について考える [コミュニティ]

先日、図書館でふと目に止まったのが畑村洋太郎氏の「組織を強くする技術の伝え方」という本であった。失敗学のすすめなどで有名な先生である。比較的薄い本でさらりと読めてしまったので、印象に残ったこと、考えたことを簡単にメモしておく。

伝える上で大切なこととしてまず言っていることは、受け入れの素地を作ること。これは知識の吸収は、伝えられる側の知識を吸収しようとする意欲に大きく関係するため、そのような状況を作りだすことが大切ということである。そのためには、本人が自発的に動くような状況を作ったり、また、脳の要求を利用し、マズローによる人間の5段階の欲求にある自己実現の欲求をうまく利用することも良いらしい。その上で、技術を伝える方法について以下の5つのポイントを紹介している。

 ・まず体験させろ
 ・はじめに全体を見せろ
 ・やらせたことの結果を確認しろ
 ・一度に全部を伝える必要はない
 ・個はそれぞれ違うことを認めろ

これはその通りだなと思ったのだが、これ以上に1つ面白いと思ったのは、著者がここでいう「技術」の定義である。技術は、「知識やシステムを使い他の人と関係しながら全体を作り上げていくやり方」と定義している。つまり、個人に閉じた世界でのやり方ではなく、組織あるいはチームである製品開発をしたりするためのやり方が技術である、と言っているのである。技術が伝わらないと、組織として競争力のある製品を世に送り続けることが難しくなったり、(品質の問題から)望まぬ事故を引き起こしたりすることに繋がったりする、という訳である。

上記定義に照らし合わせれば、これは製品開発に限った話ではなく、SIの中にも伝えていくべき多くの技術があるのではないかと考えさせられた。要するに、「全体」というのを、「ITシステム」あるいは「ITサービス」と言い換えるとわかりやすいかもしれない。例えばデータベース技術者として、知識やシステム(ベンダ製品)を使い他の人と関係しながらITシステムを作り上げていくやり方、には具体的に何があるだろうか。ぱっと思いつくことだけでもいくつか挙げられる。

 ・APの動作に必要なデータベースの環境要件を適切に捉え設計・構築するDB基盤構築技術
 ・APに必要なデータを格納するテーブル(パーティション)・索引を設計・実装するモデリング技術
 ・試験に必要なテーブルを作成したり、データをロードしたり、バックアップ・リストアするデータ管理技術
 ・データベース製品のアーキテクチャを踏まえ、効果的なAPの処理方式を決定する処理方式設計技術
 ・APの性能を担保するための性能確保技術、性能遅延に伴う性能(SQL、インスタンス)チューニング技術
 ・データベースの障害(結果不正、データ破壊、インスタンスダウン等)に伴う解析やトラブル対応技術

これらに関して言えば、テクノロジーは変われどSIの中での必要性は今も昔も変わっていないと思う。もちろん、時代によって製品機能や利用できるサービスは変わるので、蓄積する技術の重要性は変遷するだろう。例えばクラウド時代においては、環境構築やバックアップはボタン1つでできるので、技術の蓄積の重要度が下がるだろう。一方、面が簡単に増やせるだけに、より多数の面を管理しなければならないため、データ管理技術の方がより重要性が増すだろう。OracleのautonomouseやAP透過なIn-memoryが功を奏せば、チューニングの重要性は減っていくかもしれない。しかし、よりクラウドというサービスでブラックボックス化された中でトラブルが発生した場合は、より高度なトラシュー力が求められるかもしれない。自動パッチでしょうもない不具合に悩まされることは減っても、設計に起因するトラブルは避けられないので、設計・サイジングは変わらず重要、といった具合である。

私がよくノウハウとして残すドキュメントは、Oracleに関する以下のようなものである。
 ・致命的不具合など、同じバージョンで他のPJでも発生するようなクリティカルなもの
 ・製品の基本的なアーキテクチャ
 ・新機能のユースケースとして役立つ利用技術

これらは、かなりOracle製品に特化したノウハウであり、上記の定義からは技術と呼ぶには難しいかもしれない。特に不具合情報などは長期的に見れば一過性のものであり、いずれPSUに取り込まれるからである。しかし、例えば、運用中にOracleの12.2である不具合に遭遇したとする。発生事象から、問題を切り分け、本質的な問題(不具合)を特定し、運用中の暫定対処(隠しパラメータの変更等)、本格対処(パッチ適用)という一連の流れを他者とかかわりあいながら実施することとなる。もしトラシュー技術なるものがあるとすれば、不具合情報を伝えるというより、一段メタな対処のプロセスや考え方なのではないか。

また、アーキテクチャについては、これがアーキテクチャの説明にとどまらず、APの処理方式や運用に関する何らかの規約(べし・べからず集)になるものであれば、これは他の人と関係しながら作り上げるやり方(技術)と呼べるのではないか。例えば、APはバインド変数を使うこと、DDLは業務繁忙時間帯の実行は避けること、等である。また、新機能についても、例えばマルチテナントにより、面の展開がクローンコピーで楽にできるようになるといった、データ管理のユースケースに紐づけば、これも技術と言ってよいかもしれない。

Oracle技術者として5年10年経てば、多かれ少なかれ若手を指導する機会が出てくるだろうし、何から始めようと悩むこともあるだろう。そこで伝えていくべき技術とは、構築ならrunInstallerでDB構築する方法だったり、運用ならAWRのtop10の待機イベントの読み方だったり、様々であろう。しかし、それらの知識は単体で存在するわけではなく、上記のような様々な場面(ユースケース)において多かれ少なかれ他者とかかわりあいながら物事を進めていくために存在しており、その位置づけを理解することが、「受け入れの素地づくり」に決定的に重要なのかもしれない。体験させて、全体を見せることにより、受け入れの素地が作られれば、おのずと吸収の環境ができる。そうすればより効率よく本質的な技術を伝えていけるのかもしれない、と考えるのである。そういう伝え方ができていたか、振り返る良い機会になった。

なお、本Blogで記載している多くの記事は自分のための備忘(将来の自分への思考の記録)と、もしかすると他システムへの共有で役立つことがあるかもしれない、という期待が少しある。不具合事象の共有は賞味期限は短い(ただ、インパクトが大きければ価値はあるだろうが)が、上記技術に対する考え方やアプローチは、抽象度は上がるものの、時代や組織を超えて長く使えるものとなるに違いない。そういう記事を残していければよりDBAの世界平和にわずかながらでも貢献できるのかもしれない。

以上

◆参考文献

組織を強くする技術の伝え方 (講談社現代新書)

組織を強くする技術の伝え方 (講談社現代新書)

  • 作者: 畑村 洋太郎
  • 出版社/メーカー: 講談社
  • 発売日: 2006/12/19
  • メディア: 新書



nice!(0)  コメント(0) 

トランケートとORA-00054: resource busy and acquire with NOWAIT specified or timeout expired [SQL・DDL]

台風19号が過ぎ去り被害の報道にこの台風の爪痕の大きさに驚くとともに被災された方々には1日も早い生活の復旧を願うばかりである。

ORA-54は一般的にロック中のテーブル(レコード)に対し、SELECT ... FOR UPDATE NOWAIT等でロックを獲得しようとした場合に発生するエラーである。ロック中のオブジェクトに対しロックをかけようとしているため、このオブジェクトへのロック解除後に再実行すれば解消される。この際、NOWAITではなく、SELECT ... FOR UPDATE WAITでタイムアウトを設定すると、指定された秒数までロック獲得を試み、失敗した場合にエラーとなる(この場合はORA-30006)。ロックとの競合で即時エラーを回避したい場合に有効である。

このORA-54、DML実行中のテーブルにトランケートを実行しても発生する。これはトランケートは該当オブジェクト(セグメント)に対しTMエンキューを排他モードで獲得するためである。alter table ... truncate patitionで複数のパーティションにトランケートを順に実行するとき、たまにORA-54が返って失敗するのは、多くの場合DML(オンライン処理などの業務アプリケーション)との競合が発生し、トランケートがロック獲得に失敗したためである。なお、SELECT実行中のテーブルにトランケートを実行した場合、トランケートでORA-54は発生せず処理されてしまう。SELECTは(Oracleの場合読み取り一貫性のメカニズムにより)ロックを獲得しないためである。トランケートの結果、data_object_idが変わってしまうため、SELECT側にORA-8103: object no longer existsが返る。

トランケートのORA-54を回避するには、当たり前であるがDML実行中にトランケートを実行しないことである。そもそもDML実行中にトランケートを実行しなければならないこと自体に疑問はありつつも、現実問題として、トランケート実行タイミングに影響ある業務APを完全に制御し切れないケースもあるだろう。このような場合に有効なのが、11gから導入されたDDL_LOCK_TIMEOUTパラメータである。例えばこれを以下のようにセッションレベルで設定すると、指定された秒数までDDLのロック獲得を試みることができる。多少のDMLとの競合であれば、DML実行の間にロック獲得を試みて、トランケートの成功確率を高めてくれるので便利である。なお、このデフォルトは0(秒)なので、ロック獲得に失敗したら即ORA-54が返却される。

 alter session set ddl_lock_timeout=60;

TMエンキューに限って言えば、トランケートはセグメントレベルでロックを獲得する。つまり、パーティション表において、ORA-54が発生するのは、あくまで別トランザクションがそのタイミングで該当パーティションにDML操作を行っていた場合に限られる。したがって、例えば日付レンジパーティション表で、使われなくなった過去パーティションをトランケートする場合には、ORA-54の発生確率は低いだろう。逆に、ハッシュパーティションやリストパーティションで、どのパーティションも頻繁にDML操作される状況においては、いくつかのパーティションでORA-54が発生しトランケートが失敗したりする。このような場合に、上記DDL_LOCK_TIMEOUTは非常に有効である。

ただし、パーティションの競合が無いからといってオン中のトランケートを実行しても大丈夫という訳ではない。ORA-54は避けられても、トランケートにより当該テーブルにアクセスするSQLのカーソルのinvalidation、およびそれに伴うハードパース、それがトランケートによるテーブルレベルのlibrary cache lockと競合することは避けられないためである。このあたりの挙動の詳細は記事「トランケートについて知っておくべきこと」を参照されたい。

なお、DDL_LOCK_TIMEOUTはトランケートに限らず、ALTER TABLE・INDEX等のパーティションメンテナンスのDDLにも有効である。例えば、ローカルインデックスリビルド(alter index ... rebuild partition ...)、未使用エクステントの開放(alter table ... modify partition ... deallocate unused)など、パーティションメンテナンスの実行時にORA-54が発生した場合、回避策の1つとして考慮するとよいだろう。

以上
nice!(0)  コメント(0) 

UTL_FILEがNLS_LANGで結果不正 [アーキテクチャ]

先日、業務チームからUTL_FILEで出力したファイルがおかしいという問い合わせがあった。調べてみると、最後の文字がなくなったり、不要な改行が追加されている部分があり、それも文字の種類によって規則性がある、というものであった。環境はOracle19c(Exadata)、データベースのキャラクタセットはJA16SJISである。

結論から言うと、この事象の原因はDBインスタンスを構成する各種プロセスのNLS_LANG環境変数がデフォルトのAMERICAN_AMERICA.US7ASCIIとなっていたことであった。DBサーバのoracleやgridユーザのNLS_LANGをSJISに設定し忘れた訳ではない。以下のように、Grid Infrastructure(GI)にNLS_LANGを設定することにより、当該事象は回避できた。この設定はOCRに書き込まれるので永続的、ただし反映にはインスタンスの再起動が必要である(マルチテナントの場合はPDBではなくコンテナの再起動が必要)。

srvctl setenv database -d dbname -t "NLS_LANG=Japanese_Japan.JA16SJIS"

さて、以下この事象についてもう少し詳しく記載する。UTL_FILEのマニュアルの以下の記述を読んでほしい(特に最後の一文)。

---
PL/SQL Packages and Types Reference, 255.2 UTL_FILE Operational Notes
UTL_FILE expects that files opened by UTL_FILE.FOPEN in text mode are encoded in the database character set. It expects that files opened by UTL_FILE.FOPEN_NCHAR in text mode are encoded in the UTF8 character set. If an opened file is not encoded in the expected character set, the result of an attempt to read the file is indeterminate. When data encoded in one character set is read and Globalization Support is told (such as by means of NLS_LANG) that it is encoded in another character set, the result is indeterminate. If NLS_LANG is set, it should therefore be the same as the database character set.
---

UTL_FILEを使う場合は、NLS_LANGはデータベースのキャラクタセットと一致させる必要がある。そうでない場合の結果は不定(indeterminate)ということである。つまりこれはUTL_FILEの仕様、ということになる。

問題は、ここでいうNLS_LANGとは何か、ということである。例えばsqlplusのクライアントがリスナー経由でDBサーバへ接続し、PL/SQLの無名ブロックでUTL_FILE.PUT_LINE等でファイル出力するケースを考えよう。この場合、実体としてはDBサーバ上のサーバプロセスがファイル出力するため、このサーバプロセスのNLS_LANGを指すと思われる。では、このNLS_LANGはどこから来るのだろうか。普通に考えるとクライアントからの接続要求はリスナーを経由し、リスナーがこのサーバプロセスを生成することから、このリスナーのNLS_LANGが引き継がれると考えられる。リスナーを起動するOSユーザがoracleユーザであれば、その環境変数に指定されたNLS_LANGであると考えられる。11gR2まではGIが無かったので、多くの場合はOSのoracleユーザのNLS_LANGにより、Oracleのプロセス群に設定されるNLS_LANGが決定されていたはずである。そのため、UTL_FILEの上記仕様の制限を意識する必要性はあまりなかったと思われる。

しかし、11gR2以降では話は異なる。多くの場合、DBインスタンスやリスナー等のDBリソースはGIにより管理される。DBインスタンスはsrvctlにより起動停止を制御し、リスナーはGIにより自動起動される。この場合注意が必要なのは、これらのプロセスは、oracleやgridユーザのNLS_LANGの設定如何にかかわらず、デフォルトではAMERICAN_AMERICA.US7ASCIIが設定されるということである。例えoracleユーザやgridユーザのNLS_LANGにJapanese_Japan.JA16SJISしても、DBインスタンスを構成するプロセス、リスナーはNLS_LANG=AMERICAN_AMERICA.US7ASCIIになる、ということである。この状態でUTL_FILEを使うと、上記制約に引っかかる、という訳である。

この事象の回避方法は、上記で述べたとおりsrvctl setenvでDB毎にNLS_LANGを設定するしかないだろう。DBインスタンスの再起動を伴うためそれなりにインパクトがあるが、受け入れるしかない。残念ながら、試した限りではsrvctl setenv listenerだけではこの事象は回避できない(もしかすると単純にリスナープロセスのNLS_LANGだけが原因、ということではないのかもしれない)。上記設定によりDBサーバのプロセス郡のNLS_LANGが変更されることに不安を覚えるかもしれないが、クライアント側に返却される結果についてはクライアント側のNLS_LANGに依存するため、DBサーバのNLS_LANGの影響を受けない。また、リスナー経由しないDB接続(DBサーバでoracleユーザから直接sqlplus / as sysdbaで接続するなど)は、サーバプロセスもoracleユーザで起動されるため、結果そのユーザのNLS_LANGが引き継がれるため影響を受けない。とはいえ、運用中のシステムに対しこれを変更するのは勇気がいることには変わりない。

なお、DBインスタンスを構成する各種バックグラウンドプロセスが出力するalert.logやトレースファイル、これらの文字コードや言語はNLS_LANGと一切関係なく、データベースキャラクタセットと初期化パラメータNLS_LANGUAGEに依存する。そう考えると、そもそもUTL_FILEが何故DBインスタンスを構成するプロセスのNLS_LANGに依存した作りになっているのか理解に苦しむ。単純にデータベースキャラクタセットと同じ文字コードでファイル出力する、という仕様にすれば良いだけの話である。特にエラーが出る訳でもなく、文字コードの組み合わせによっては事象が顕在化しない場合もあるため、顕在化した際の業務的なインパクトが計り知れない。せめて、設定の矛盾をalert.logに出力するなど、気付くきっかけくらいは考えてくれてもよいのではないか。そう考えると、このUTL_FILEの仕様は極めて不親切であり、どちらかというと、ワークアラウンドが確立されたため修正される見込みのない不具合ではないか、という気すらする。

今回の件を通し、先のUTL_FILEの仕様を読み、それを咀嚼してOracleの環境設計に取り込めるOracle技術者はどれほど存在するだろうか、と考えさせられた。このUTL_FILEの仕様は古く9i時代にさかのぼるらしいが、11gR2からのGIの登場によりより問題として顕在化し易くなったのではないだろうか。世の中的にはあるあるネタで知っている人は多いかもしれないが、少し不安に思った方は自分の身を守るために今一度ご自身の環境をチェックされては如何だろうか。

以上
nice!(0)  コメント(0) 

Oracle Open World 2019とコミットキャッシュ [最新動向]

今年もOOWへ参加することができた。3泊5日の弾丸ツアーでかなり慌ただしかったが、帰りのフライトでようやくホっと一息つけたので、振り返って感じたことをメモしておく。

IMG_0050.jpg


今年のOOWは9/16-19と昨年と比べると1か月程度早めで、このうち私が参加できたのは初日と2日目のみであった。OOWといっても、ラリーのキーノートはライブで配信されいずれ記事にもなるので、ここで改めて書くつもりはない。また、Oracle Linuxがautonomousになっても、開発用にオラクルクラウドが無償提供されるようになっても、コーポレートカラーが赤から黒になって、雰囲気が変わったことなど、私にとってはどうでも良いことである。私が今回一番印象に残ったExadataのコミットキャッシュについて記載したい。

Exadataのコミットキャッシュとは、コミット済みトランザクション情報をストレージサーバ側にキャッシュし、未コミットブロックを遅延ブロッククリーンアウトが必要かストレージサーバ上でチェックできる仕組みである。これにより、スマートスキャンが遅延ブロッククリーンアウトにより阻害される状況を防ぐことができる。

今回OOWにて、Exadataの技術責任者の方とお話しできる機会があり、以前このブログで紹介した「exadataと遅延ブロッククリーンアウトとシングルブロックリード」の事例について説明した。すると彼女は、まず、ロングトランザクションがないことを確認した上で、即座に何らかの原因でこのコミットキャッシュが効いていない可能性を指摘した。具体的なキャッシュサイズは教えてくれなかったが、サイズは有限であるはずなので、遅延ブロッククリーンアウトまでに発生したコミット回数が多いと、キャッシュがパージされる可能性は高まるだろう。さすがに開発している技術者だけあって、原因の核心に辿り着くのが早い。

実は私もExadataの遅延ブロッククリーンアウト時の挙動は気になっており、行きのフライトの中でExpert Oracle Exadata(下記参考文献[1])の該当部分(p.388-389)をコピーして(重いので)読み直していたのだが、その中でコミットキャッシュに被疑があるのではと考えていた。簡単に訳すと以下のような内容である。若干翻訳は正確でないかもしれないが、著者の意図は変えていないつもりなので、ご容赦願いたい。

---
もしロックされたトランザクションがまだコミットしていなければ、スマートスキャンはブロックI/Oモードに切り替わり、DBレイヤで通常の読み取り一貫性の処理、つまりバッファクローニング、ロールバックといったメカニズム、を通らなければならない。そして、これを避けるワークアラウンドはない。・・・

トランザクションがコミットされているのに、いくつかのブロックのいTL上のロックバイトがクリーンアウトされていない状況(通常、大量の更新後に発生し、遅延ブロッククリーンアウトと呼ばれる)では、スマートスキャンはブロックI/Oに切り替える必要はない。読み取り一貫性メカニズムを行う必要もない。なぜなら、セルは、ロックを保持しているトランザクションは本当はコミットされており、これらの行は既にロック解除されている、ということを知っているからである。たとえ、ロックバイトが(ITL上に)まだあったとしても、である。

特定のトランザクションがRDBMS上でコミットされたことを、セルはどの様に知るのだろうか。これは、最近コミットされたトランザクションの番号をキャッシュすることで実現されており、「コミットキャッシュ」と呼ばれる。ロックバイトが設定された行を多く読まなければならないとき、コミットキャッシュがなければスマートスキャンの性能は悪くなるだろう。

コミットキャッシュは恐らく単なるインメモリのハッシュ表で、トランザクションIDで構成されているだろう。そして、どのトランザクションがコミットされたか、されていないかを記録し続ける。セルスマートスキャンがロックされた行に遭遇すると、トランザクションIDをデータブロックのITLから取り出し、コミットキャッシュ上にそのトランザクション情報があるかチェックする。このチェックで「cell commit cache queries」が1増加する。

もしコミットキャッシュにそのようなトランザクションが無ければ、スマートスキャンには不運であるが、読み取り一貫性処理をしなければならないので、遅いシングルブロックリード処理に戻る。一方、キャッシュにヒットした場合は「cell blocks helped by commit cache」が1増加する。
---

上記部分は以前、「ExadataのI/O統計を整理する」をメモした際に一度読んではいたが、今改めて読むと良く理解できる。まだ勉強が足りないなと反省する次第である。

いずれにしても今回OOWを終えて思うのは、現地開発者との距離の近さが、問題解決のスピードに決定的な違いを生むという事実である。適切な問い合わせ先組織・人に、問題を明確に伝えられれば、今回の様に1時間の打ち合わせでも、適格に問題を特定できると実感した。Oracle databaseもExadataも核心はソフトウェアであり、所詮開発者がコーディングしたプログラムに過ぎない。問題が発生すれば、普段はブラックボックス前提でサポート問い合わせし、満足いかない回答にサポートを罵るような現場は少なくない。しかし、適切な開発者と直接コミュニケーションできれば世界観が変わる。もちろん、そのようなパスは一朝一夕にできる訳はなく、この様な機会を通じてお互いの信頼関係を築いていくしかないのだろうと考えるのである。

なお、その他のトピックとしてExadata関連では、今回X8M (MはMemory performanceを表すらしい) が発表されたことである。以前「Exadataと不揮発性メモリ」で、できたら面白いと記載していたが、それが現実となった形である。しかも今回IBがRocE (Ethernet上のRDMA)に切り替え、帯域が40Gb/sから100Gb/sに向上している。これについては既にGavin Parish氏の以下のBlog記事が出ており、OOWで聞いてきた内容もおおむねここに記載されているように思う。

Introducing Exadata X8M: In-Memory Performance with All the Benefits of Shared Storage for both OLTP and Analytics

また、会場で面白そうなOracleのトラシュー本(下記参考文献[2])があったので手に取ったら、著者が昨年のOOWで講演を聞かせていただいたFarooq氏だったので、思わず(重いのにもかかわらず)買ってしまった。いつ読めるかわからないが、こちらについてもまた紹介できたらと思う。

以上

◆参考文献
[1] Expert Oracle Exadata

Expert Oracle Exadata

Expert Oracle Exadata

  • 作者: Martin Bach
  • 出版社/メーカー: Apress
  • 発売日: 2015/08/13
  • メディア: ペーパーバック



[2] Oracle Database Problem Solving and Troubleshooting Handbook

Oracle Database Problem Solving and Troubleshooting Handbook

Oracle Database Problem Solving and Troubleshooting Handbook

  • 作者: Tariq Farooq
  • 出版社/メーカー: Addison-Wesley Professional
  • 発売日: 2016/04/28
  • メディア: ペーパーバック



nice!(0)  コメント(0) 

exadataと遅延ブロッククリーンアウトとシングルブロックリード [アーキテクチャ]

exadataにおいて、フルスキャンで読み取り一貫性を発生させない(つまりUNDOへの読み込みを発生させない)ことが遅延対策のポイントになるのは言うまでも無いが、それ以外にも遅延ブロッククリーンアウトが遅延の原因となるケースに遭遇したのでメモしておく。

事象としては、1GB程度のテーブルをcsvに出力する処理(夜間バッチ)が50分(SQLレポートのelapsed time)かかったのである。クエリは単純な1テーブルへアクセスするもので母体の件数は600万件、WHERE句でフラグでフィルタしているので、出力は500万件程度。SQLトレースを取得すると、大量のシングルブロックリード(20GB以上)が発生しており、ASHからUNDO表領域へのアクセスであることが判明した。日中帯に同じSQLを実行したら16秒程度(sqlplusからautotrace traceonlyで測定)で完了する。このときスマートスキャンが発生していた(SQLトレースから確認)していたため、通常であればそもそもシングルブロックリードが発生するはずがない。このテーブルは事前にトランケート・インサートされた後にこのクエリが走るだけで、他のトランザクションはないため、読み取り一貫性によるUNDOへのアクセスが発生していた可能性はない。しかも母体のテーブルサイズをはるかに上回るUNDO量である。これは一体どういうことか。。。

一般的なOracle(非Exadata)ではFTSはマルチブロックで読み込んだブロックに対して読み取り一貫性のため必要なUNDOを読み込みCRブロックを生成する。スマートスキャンの恩恵は受けられないが、IOはマルチブロックリードにより効率的に行われる。一方、exadataではFTSはスマートスキャンとなることがあり、その場合は各ストレージサーバへFTSの処理がオフロードされる。このとき、各ストレージサーバはCRブロックを返却する必要があるが、各ストレージサーバは各ブロックが「CRブロックである」ことを認識し、ストレージサーバ毎に独立してプレディケートフィルタやカラムプロジェクションを行うのである。しかし、「CRブロックでない」、つまり読み取り一貫性の為にUNDOを読み込む必要があると、ストレージサーバはスマートスキャンを諦めてシングルブロックを返却する。そして、DBサーバ上のバッファキャッシュ上で必要なUNDOブロックを読み込み(シングルブロックリード)CRブロックを生成することを繰り返す。スマートスキャンの恩恵を受けるため、他トランザクションからの更新を避けるのはこのためである。

実はこの挙動は遅延ブロッククリーンアウトでも発生する。遅延ブロッククリーンアウトは、簡単に言うと最新化されていない未コミット状態のブロックをコミット時ではなく、後でコミット済みに変更するメカニズムである。これが発生すると、ブロック読み込み時に、そのブロックがコミット済みかどうかを確認するために、ITLに記録されるトランザクションID(xid)から、UNDOセグメントヘッダのトランザクション表へアクセスする。コミット済みであることが確認できれば、そのブロックのITLをコミットSCNとあわせてコミット済みに変更する。ブロックへの変更が発生するため、(たとえSELECTであっても)REDOが発生する。

また、UNDOセグメント毎のトランザクション表のスロット数はOracleのバージョンやオプションにより決まる(34,48,96個等)。また、1つのUNDO表領域上に作成できるUNDOセグメント数にも上限があることから、必然的にトランザクション表のスロットは上書きされてしまう。このため、コミット時のSCNを確認するため、トランザクション表への読み取り一貫性、つまりUNDOをたどって過去のSCNを確認するという挙動が発生することもある。これらUNDOへのアクセスは、すべてDBサーバからシングルブロックリードが必要である。

ストレージサーバはCRブロックであることをどのように判断するのだろうか。各ブロックのITLにはそのブロックにアクセスするトランザクション(xid)とその状態(コミット済みがどうか等)、コミット済みSCN、関連するUNDOブロックアドレスが記録されている。したがって、オフロードされたクエリのSCNがコミットSCNより新しければ、そのブロックはCRブロックと判別できるはずである。未コミットのトランザクションがある場合、またはコミット済みでもクエリのSCNがコミットSCNより古い場合はUNDOブロックを読む必要があるので、シングルブロックを返却する流れとなる。実際はもっと複雑な流れだとは思うが、おおまかにはこんなところだろう。

では、遅延ブロッククリーンアウトの状況ではどうだろうか。遅延ブロッククリーンアウトは、コミット済みであるにもかかわらず、ブロックは未コミット状態となっている状況である。上記ロジックが正しいとすれば、この状況は必ずUNDOの読み込みが必要となるため、スマートスキャンはできなく、シングルブロックを返却する流れとなることは容易に想像がつく。

遅延ブロッククリーンアウトが発生する要因の一つは、バッファキャッシュの枯渇である。未コミットのダーティブロックが、トランザクション完了(コミット)前にDBWRによりパージされてしまうと、トランザクション完了してもディスク上には未コミット状態のままとなる。このため、更新時のバッファキャッシュを増加させれば発生頻度を減らすことが可能である。もちろん、コミット間隔を小さくすることも対策として有効だろう。また、UNDOへのアクセスを減らすという意味では、トランザクション表(のスロット)が上書きされなければ、トランザクション表に対するUNDO読み込みは不要となる可能性があるため、更新直後に読み込む、という対処も有効なはずである。

あくまで仮設であるが、今回の遅延事象は、INSERT時(2000件単位でコンベンショナルINSERT・コミット)のバッファキャッシュ上のブロックが、他処理との並走によりバッファキャッシュが不足し、未コミット状態でディスクに反映されたものが増えた。また、コミット後からクエリまで2時間程度経過していたことから、トランザクション表が上書きされ、コミットSCNを確認するためにトランザクション表のUNDOを読み込む必要がある状態になっていた。このため、後続のフルスキャンで遅延ブロッククリーンアウトが発生し、UNDOへの読み込みが必要なことからスマートスキャンは効かず、UNDOへのシングルブロックリードを発生させたのではないか、と考えた。実際、バッファキャッシュを2倍程度に変更することで、50分かかっていたクエリが10秒以下にすることができた。簡単に2つの処理の違いを比べると、如何にExadataにおいて遅延ブロッククリーンアウトの際のオーバーヘッドが大きいかわかる。

◆通常のスマートスキャンの挙動
フルスキャン→ダイレクトパスリード→スマートスキャン(マルチブロックリード)→ストレージオフロードによりフィルタ済みブロックのみ返却→結果セット

◆遅延ブロッククリーンアウトの際の挙動
フルスキャン→ダイレクトパスリード→スマートスキャン→ITLが未コミットなのでシングルブロックで返却→UNDOセグメントヘッダ読み込み→コミットSCN確認のためトランザクション表のUNDO読み込み→コミットクリーンアウト→UNDO変更のREDOチェンジベクター生成→バッファキャッシュ上でフィルタ処理→結果セット

遅延ブロッククリーンアウトが発生したことを示すことは一般的に難しいとされる。今回はAWRやASHから得られる情報から消去法的に仮設を作り上げた。ただ、それでもなお、今回なぜこれだけの量のUNDOを読む必要があるのかまでは追いきれなかった。この事象を通して遅延ブロッククリーンアウトについて改めて理解を深めることができたのは、やはりJonathan Lewis氏のOracle Coreによることが大きい。Exadataや最新のOracleバージョンには記載はないが、根本のアーキテクチャは変わらないものである。

わかればわかるほど、わからないことを知る、ということを感じる今日この頃である。

以上

◆参考

Oracle Core: Essential Internals for DBAs and Developers (Expert's Voice in Databases)

Oracle Core: Essential Internals for DBAs and Developers (Expert's Voice in Databases)

  • 作者: Jonathan Lewis
  • 出版社/メーカー: Apress
  • 発売日: 2011/12/06
  • メディア: ペーパーバック



nice!(0)  コメント(0) 

19c新機能 ~ Oracle Cloud Days [最新動向]

8/6,7に新高輪で開催されたOracle Modern Cloud Day Tokyoの1日目に参加し、19cの新機能についての話を聞いてきた。内容は概ね以下のスライド通り。3点ほど気になった点があったので以下にメモしておく。

2019/4/22 TechNight資料

1点目。プレゼンを聞いていてリアルタイム統計がデフォルト有効、かつ、無効化するにはヒント(NO_GATHER_OPTIMIZER_STATISTICS)を使うという話があった。しかし現実問題、更改案件では無効化するために全てのSQLにヒントを入れることは不可能なので、この話は受け入れがたい。性能負荷はわずかである(minやmax、num_rowsといった最小限の統計のみ取得する)といいつつも、負荷もさることながら、統計変動による実行計画変動を避けたい、というニーズは変わらず存在するからだ。

実際、以下の初期化パラメータを設定(FALSE)することで無効化できる。隠しパラメータなので、おそらく積極的に設定されないよう、あまり公にしたくないという意図が感じられた。

"_optimizer_use_stats_on_conventional_dml" ・・・リアルタイム統計を使用するか制御するパラメータ
"_optimizer_gather_stats_on_conventional_dml" ・・・ リアルタイム統計を収集するか制御するパラメータ

また、12cからのダイレクトインサート時(CreateTableAsSelectやInsertAsSelect)の統計収集機能もある。これもヒントで制御できるが以下の初期化パラメータで無効化できる(デフォルト有効化)。

"_optimizer_gather_stats_on_load"

経験上、これは取得にそれなりの負荷がかかるので、意識してインサート時に統計取得したい!、という場合の除いて無効化しておくことが良いだろう。DWHの一時表など、そもそも取得の必要がない、あるいは統計ロック等で変動を抑える対処を検討済みのシステムを更改する場合などではなおさらである。

2点目。19cの高頻度自動オプティマイザ統計収集は、15分間隔でstaleになったテーブルの統計を取得する機能であるが、これが実装されたのは興味深い。以前、同様な機能を作りこもうとしている人をOracleコミュニティで見たことがあったからだ。DWHでロードするタイミングが複雑で、適切な統計取得のウィンドウを1つに決められないケースだったと記憶している。デフォルトオフなので、あまり気にすることはないが、何かに役立つかもしれないので覚えておきたい。

3点目。上記プレゼンの中で、自動インデックスのデモがあった。単純なフルスキャンの実行計画が自動インデックスにより1秒以下にチューニングされたというもの。正直、これだけでは商用でまともに使える感触までは得られなかったが、AUTO_INDEX_MODE=report onlyでレポートだけ作成してくれる機能があるので、例えば開発環境でバッチを一通り流してどのような自動インデックスが作成されるか見るという使い方はできるかもしれない(ただ、それならSQLアドバイザとかを使えばよいだけかもしれないが)。感覚的にはインデックス作成によるチューニングは入念な試験を経て初めて商用リリースできると思っているので、15分間隔のサイクルで自動で新たなインデックスが有効化される、という世界観がどれだけ受け入れられるのか、今後の動向を注視したい。

以上
nice!(0)  コメント(0) 

JPOUG 2019 presentation slide (English) [コミュニティ]

Please find my presentation slide (English) in JPOUG held on July 23, 2019. The content is mostly based on my previous post about truncate, but I have also mentioned new features in 12c.



nice!(0)  コメント(0) 

JPOUG 2019へ参加したときのこと [コミュニティ]

 去る7/23に月島でJPOUGというOracleのコミュニティが開催された。JPOUGとは日本のOracleコミュニティである。Oracle Databaseを中心とした情報交換を目的として、年に数回、セミナなどを開催している。今回は15分で好きなことを話すという催しであり、今回で8回目だそうだ。今回はここで、1セッション講演させて頂いたときの話である。

  JPOUG in 15 minutes #8

 社外での講演自体自分にとって初めての経験だったので、この話を頂いたときは引き受けるか一瞬迷った。しかし、どんな世界なのか興味があったのと、もともと社内外問わずOracleにまつわるDBAの生活の質を向上に貢献したいという思いもあり、引き受けすることにした。テーマは本Blogでも記載している「トランケートについて知っておくべきこと」。誰でも知っていると思っていることの裏に奥深い世界があること、開発や運用上それが役立つことがあるということをを少しでも伝えたかったからだ。

 会場には50名ほどであろうか、仕事が終わってだんだん席が埋まってくる。講演者は自分含め6人(1人は体調不良とのことでキャンセル)、休憩の後に私の時間となったが、その頃には会場は一杯になっていた。ここ連日、終電まで仕事をしていることが多く、発表の練習をする時間がなかったのが心配だった。というのも15分という時間は曲者で、油断するとついつい余計な事を話過ぎてしまうのだ。用意した資料は通常の自分では30分~45分はかかる内容だっただけに、ポイントを絞って余計なことを話さないように気をつけた。内容は概ね本Blogに記載した以下のトピックである。
 
 ・トランケートについて知っておくべきこと
 ・トランケートの非同期グローバル索引メンテナンスについて
 ・遅延カーソルインバリデーション

 発表後、懇親会でコミュニティの方とお話しすることができた。正直、あまり人付き合いは得意な方ではないのだが、技術の話になれば初対面の方でも通じ合える世界があることを痛感した。この中で、「トランケートで15分も話すことがあるのか?この人大丈夫か?」と思った、と率直な感想を聞けたのが面白かった。というのも、自分は15分にどう納めるかを必死に考えていたからだ。Blogは一方通行で記事の内容が誰にどう伝わっているのかわからないが、このように生のフィードバックがあると励みになる。また、このBlogの存在も急にアクセス数が増えて驚いた。一瞬しか投影していないのに。

 今後、また機会があれば参加していきたいと思った。内容が同じでもBlogに記載するのとface to faceで伝えるのとは違う。内容は悩ましいが、私が話すとしたら基本アーキテクチャの話やチューニング事例、運用(効率化)ネタあたりが良さそうである。逆にトラブル(不具合)系やExaなどのエンタープライズ系はあまり良くないかもしれない。クラウドも流行りではあるがそもそも自分が興味がない。新機能紹介はOracleさんにお任せで良いだろう。このような経験をつめば、いつかOOWで話をすることができるか。。。一瞬、帰りの電車で夢みたいなことを考えてしまった。

なお、資料は準備ができたらそのうち公開しようと思っている。少しお時間頂きたい。

2019/7/30:追記 以下に公開:
https://www.slideshare.net/KazuhiroTakahashi5/oracle-158890029

以上
nice!(1)  コメント(0) 

遅延カーソルインバリデーション [SQL・DDL]

以前、トランケートについて知っておくべきことで述べたように、DDLは(data_object_idの変更とともに)関連するオブジェクトの共有カーソルを即時に無効化していた。しかし、実はOracle12cR2からは、可能なものは無効化を回避し、避けられないものはローリング無効化を行うことができるようになっている。このあたりの挙動は実は設計や運用上、きわめて影響の大きい内容の割には、あまり詳しく説明したドキュメントがパブリックになっていないような気がする。津島博士によるドキュメントは参考になるが、トランケートの際の挙動が記載されていない。そこで、実際に自分で確かめてみようと考えた。

トランケートの場合、以下のようにdeferred invalidationオプションをつけることにより、共有カーソルの無効化を(可能な限り)回避することができる。

例) alter table scott.sales truncate partition sales_q1_2006 update global indexes deferred invalidation;

実際に検証してみた結果、deferred invalidationオプションにより、以下のような効果があることがわかった。

・フルテーブルスキャン、またはローカルインデックスによるレンジスキャンではカーソルの無効化を回避できる
・グローバル索引によるレンジスキャンではカーソルは即時無効化される

※詳細なログは以下参照:
https://community.oracle.com/people/Kazuhiro/blog/2019/05/31/partition-truncate-with-deferred-invalidation?customTheme=mosc

パーティション表による過去パーティションメンテナンスによりトランケートやドロップ運用を行うことは多いと思うが、このオプションによりグローバル索引を使用していなければカーソルの無効化、ひいてはハードパースを避けられるということで、こんなすばらしい機能改善はないと思う。個人的には華々しく宣伝しているオプティマイザの適応なんとか最適化とかより、ずっと広く世の中のDBAの幸せに貢献する機能であるように思う。

なお、オプションをつけない場合の挙動はCURSOR_INVALIDATION初期化パラメータに依存するが、デフォルトは12.2も19cもIMMEDIATEである。これはDEFERREDになる日が来れば、このオプションをもはや気にする必要はないだろう。(参考:Oracle Database Reference Manual 19c, CURSOR_INVALIDATION)

ただ、実際に商用で使った経験がないため、副作用についての留意は必要だと思っている。以下でコミュニティに問い合わせをしてみてはいるので、そのうちワールドワイドでなんらかの知見が得られることを期待したい。

https://community.oracle.com/thread/4281580

以上

nice!(0)  コメント(0) 

19cにアップグレードしてTO_DATEで困った話 [SQL・DDL]

2019年5月1日、日本が令和を迎えるとき、私はExadataを12.2から19cへアップグレードする作業を行っていた。プロジェクトは開発期間とはいえ運用開始に向けての試験が詰まっていおり、この10連休というまたとない長期間DBを停止されるタイミングを狙ったという訳である。個人的にDBのアップグレードという作業は(長年Oracleにかかわってきたものの)初めての経験であり、そもそも可能な限り「避けるべきもの」、という位置づけであった。しかし、今回どうしてもとなったのは、長期保守の観点でやはりターミナルである19cに上げたい、ということとなったのである。あるいみ、DBの元号変更をこのGWに経験した訳である。

一言にアップグレードといっても、実際の作業をイメージするのは難しいかもしれない。DBのアップグレードは通常DB/GIを上げることを指すが、Exadataの場合これに加え、ESS(IBSW含む)、ZFS、EMを含めて整合性の取れた形にする必要がある。また、DB/GIとESSのバージョンは依存関係があるため、ESSだけ先走ってあげてしまうと、サポートされていない組み合わせになることもある。
そのため今回は一度DBにRUを当てて、ESSを上げられる状態にし、ESSを上げ、再びDB/GIを上げてという手順を取った。当然、この前後にミドルの落とし上げやOS・DBのバックアップ等の作業を含めると、かなりの作業量となる。手順を確立する上で、アップグレードの事前検証は必須であるが、それがあったとしても、環境差異を完全に吸収することはできないため、ある程度のリスクは想定しなければならないだろう。連休中などサポートが手薄な状況で最後に頼れるのはいつも人である。

さて、全体的にアップグレードにより12.2で踏んでいたORA-600系の不具合やいくつかのExadataのクリティカルイシューが修正されたことは純粋に喜ばしいことであった。以前このBlogでも紹介したスマートスキャンの結果不正についてもこのバージョンで修正されていることを確認している。Oracleの不具合の多さ、品質に疑問を感じることも少なくないが、一方でかなりの不具合は既に修正が出ていることが多いため、パッチを当てることができさえすれば問題を事前に回避することはできると思っている。あくまでもパッチを適用できれば、の話であるが。

一方、アップグレードにより発生した新たな問題もあった。Oracleコミュニティに投稿したが、19cでTO_DATEのフォーマットのマッチングのチェック仕様の一部が変更されたのである。以下を見てほしい。

*12.2.0.1
SQL> select TO_DATE('20190520','YYMMDD') from dual;

TO_DATE('20190520
-----------------
20190520 00:00:00

*19.2.0.0
SQL> select TO_DATE('20190520','YYMMDD') from dual;
select TO_DATE('20190520','YYMMDD') from dual
*
ERROR at line 1:
ORA-01843: not a valid month

基本的に上記で指定しているYYMMDDはYYYYMMDDと記述すべきであり、19cでエラーになる・ならないに関わらずこのような曖昧な記述は避けるべきである。しかし、実はSQLリファレンスマニュアルにYYのマッチングに失敗したらYYYYを試すという挙動が記載されている。これは自分も知らなかったので正直驚いた。

---
SQL reference manual / String-to-Date Conversion Rules

The following additional formatting rules apply when converting string values to date values
...

-If a match fails between a datetime format element and the corresponding characters in the date string, then Oracle attempts alternative format elements, as shown in Table 2-20.

Table 2-20 Oracle Format Matching
original format element:'YY' --> additional format elements to try in place of the original: 'YYYY'
---

この挙動、興味深いのは19cにおいて TO_DATE('20120520','YYMMDD')はエラーにならないのである。20→YY、12→MMにマッチングさせるところで、月のチェックが通るためと思われる。このため、データの内容に応じてエラーになる・ならないが変わるのである。また、TO_DATE('2019/05/20','YY/MM/DD')は19cでもエラーは出ない。/により曖昧さが排除されている結果と思われる。同様な関数としてTO_TIMESTAMPが気になるが、こちらは12c・19cの挙動に変更はなさそうであった。どうやらコード(実際は構文を解析するパーサだとは思うが)が異なるためらしい。

なお、多くの日本で稼動しているOracleDatabaseにおいて、Table 2-20 Oracle Format Matchingに記載されているYY→YYYY以外のフォーマットマッチングについて、同様の事象が発生するのはRR→RRRRのみである。それは、上記のNLS_LANGが日本語の場合、MONとMONTHのフォーマットに違いはなく、いずれも「7月」といった文言を変換できる。また、TO_DATE('7月','MONTH')は必ずエラーとなる挙動は12c,19c変わらずである。

OracleとしてはこのTO_DATEの挙動変更はあくまで「仕様」であり、不具合ではないというスタンスらしい。このため、19cへのマイグレーションにおいてはSQLの非互換として意識しておく必要がある。しかし、この手の細かな仕様変更はリリースノートに記載されていないから厄介である。なぜこの事象に気がついたか、経験のあるDBAなら察していただけるであろう。世の中のSQLが、このようなOracleのニッチな仕様を前提として動いていないことを祈るばかりである。

以上
nice!(0)  コメント(0) 
前の10件 | -

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。