kagamihogeの日記

kagamihogeの日記です。

どのようにOracleを勉強してきたか

一昨年から去年にかけては、リレーショナルデータベースの分野の学習に注力すべく活動を続けてきた。具体的なRDBMSのプロダクトはそのときの仕事で使っていたという理由でOracleを選んだ。学習内容としてブログでまとめたものは、主に実行速度に影響を与える要素を中心にした。年末年始ということもあり、このエントリでは、Oracleのパフォーマンスに与える影響をどのようなやり方で学習を進めてきたか、を振り返りたい。

まずはインプット

f:id:kagamihoge:20090905013101j:plain

当初の俺のOracleレベルは「スキーマってなんだ、カレーの一種か?」とかそういうレベルであったが、この程度の状況だとそもそも何を学習したいのかを自分で判断できない。だから、ともかく分かんないことがあってもいいから、最初は情報を沢山仕入れることから始めた。俺は、俺にとっては新しいことを学ぶとき、まずインプットを多くすることから始めるタイプである。たいてはまず書籍を読むことから始める。

ここでは、インプットを得るのに印象的であった書籍を三つ紹介する。

達人に学ぶ SQL徹底指南書

達人に学ぶ SQL徹底指南書 (CodeZine BOOKS)

達人に学ぶ SQL徹底指南書 (CodeZine BOOKS)

OracleというかSQLの解説書である。しかし、RDBMSSQLは切っても切れない関係があり、俺にとってはここからリレーショナルベータベース学習の糸口が始まった、という点で大変印象に残っている。リレーショナルデータベースを勉強したい、と考えたとして、果たしてどこから手を付けるのが良いのか? ソレに対する俺の回答は本書である。リレーショナルデータベースという広大な世界、まずはプログラマにとって身近なSQLから始めるのが良い手ではなかろうか。

この本で書かれているSQL(自己結合やらCASEやらEXISTSやら)を色々試したり考えたりしていると、少しずつリレーショナルデータベースの理解が進んでいく。あるいは誤解が解けていく。もっと集合論の世界を知りたいと思わせてくれる、揺りかごの役目を果たしてくれた一冊だった。

達人に学ぶ SQL徹底指南書 - kagamihogeの日記

プロとしてのOracleアーキテクチャ入門

プロとしてのOracleアーキテクチャ入門 Oracle現場主義

プロとしてのOracleアーキテクチャ入門 Oracle現場主義

揺りかごからハイハイを始めたあと、Oracleの全体的なアーキテクチャに興味が向いた。そして、Oracleの勉強をするに当たっては手元に一冊置いておきたいのがコレ。正直に言うと、初見ではほとんど何書いてるかわかんなかった……キーマカレーとかほざいてるくらいだから当然の話なのだが。

しかし、後々Oracleのパフォーマンス関連をアレコレ調べ始めたとき、この本は多いに役立ってくれた。例えば、コミットしたときってREDOログはREDOログファイルに書き込まれるんだっけ? 他に書き込まれるときってどんなだっけ? など。Oracleを実際に動かしたときの動作と、その動作のアーキテクチャ上での位置付けとを結びつけて理解するのに大変有用な一冊である。これにプラスOracle Databaseオンライン・ドキュメント 11g リリース2 (11.2)を逐次照らし合わせることでも理解が深まっていく。

プロとしてのOracleアーキテクチャ入門 - kagamihogeの日記

データベースパフォーマンスアップの教科書 基本原理編

データベースパフォーマンスアップの教科書 基本原理編

データベースパフォーマンスアップの教科書 基本原理編

Oracleのパフォーマンスの基礎に関してはこの一冊で十分だと思われる……若干分厚いが。初心者にはちと敷居高く感じる一冊だが、じっくり読み進めていく覚悟があれば、見た目の印象ほどの難易度ではない。

俺がこの本を読もうとした切欠は、実行計画の読み方が知りたかったからだった。ネットをぐぐると、実行計画を構成している個別の要素一つ一つを解説してるページは幾らでも見つかるが、体系的に解説しているページは中々見当たらなかった。だから本書を読むことにしたのだが、かなりの遠回りにはなったものの、結果的には正解だったように思う。

実行計画を読むためには、テーブル・インデックス・ビューなどOracleのオブジェクトの理解がまず必要で、そうしたオブジェクトへのアクセスパス、ジョイン方式、RBOとCBO……てな具合にすべて繋がっている。それらを一つ一つ理解してまわって実行計画に戻ってくる頃には、おおむねパフォーマンスに関わる要素の基礎の学習は終わっていた、という感じ。

この本でパフォーマンス関連の基礎知識がついたのは元より、Oracleに対する「巨大で複雑で何が起きるかわからない」不安が払拭されたことの方が大きかったかもしれない。

データベースパフォーマンスアップの教科書 基本原理編 - kagamihogeの日記

他に読んだ本に関しては書籍感想 - kagamihogeの日記を参照してください。

どのように学ぶべきか?

f:id:kagamihoge:20140103170808g:plain
インプットを続けていくうちに、Oracleはとんでもなく巨大で複雑な代物だということが分かってくる。リレーショナルデータベースという切り口でいけば更に広大な領域が拡がっている。となると、Oracleで食っていくわけでもあるまいし、すべてを理解しようとするのはちょっと筋が悪いように思えてくる。とすると、何かしらの切り口を設けてそこから攻めていくのが良さそうである。

自分の立ち位置は、アプリケーションのプログラマである。アプリケーションとは、最近の俺にとってはJavaのWebアプリケーションである。アプリから見たOracleは、何が重要な関心事になるだろうか? 俺は、性能だと考えた。もっとカンタンな言葉に言い換えてしまえば、実行時間の速さである。「Oracleが遅い」という愚痴はまぁ良く聞くことであったし、本当にOracleが遅いのか、Oracleの使い方がマズくて遅いのか、その切り分けぐらいは出来るようになりたい、という欲求が実務上で発生していた。

身近なテーマを個人学習のテーマに据えた、と言ってよいかもしれない。そう決めたあとは、実行時間*1を左右しそうなOracleの要素を片っ端から実際に動作を確認していくこととなった。やることとしては、実際に環境を作ったりコードを書いてみて、Javaからみた実行時間がどのくらい変化するのかを見る。そして、変化した理由はOracleアーキテクチャを踏まえるとどのような説明が付くのか、リファレンスや書籍をもとに裏付けを取る。それら一連の活動で新たに疑問が生じれば、それを次の学習のネタにする……以下、同じことの繰り返し。

学習した内容は、このブログのエントリの形式でアウトプットしている。てなわけでこっからは、俺がどのようにOracle関連エントリを書いているか、を書いていきたい。

二種類しかない環境から始める

f:id:kagamihoge:20140103171140j:plain

実行時間に影響のある要素を試すといっても様々なことが考えられるので、一つ一つやっていくことになる。これは、一回のエントリで学ぶことは一つに絞る、ということを意味している。あまり経験が無い内に複雑なことをやると、かえって手に負えなくなりがちなことを反省した結果である。

二つ以上の要素を同時に扱うと、急に複雑さが上昇する。たとえばAとBと二箇所を変更したとき、Aの要素がどのくらい影響して、Bの要素がどのくらい影響したのか、それともAとBの複合技によって何らかの影響が出たのか。変化が出れば良いけど、AとBが干渉して何も変化が出なかったとしたら……こうなってしまうと最悪の場合、間違った結果から間違った知識を学んでしまう恐れがある。

本番で動作しているOracleは色々と複雑なことになってるので、そういう状態を確認したいならそれでも良い。しかし、学習が目的であれば単に戸惑いが増えるだけなのでこういう複雑さは邪魔である。まずは、単純な状態の知識を積み重ね、それから複雑な現実世界のOracleに応用していくのが良いだろう、と俺は考えた。

よって、その変更以外に実行速度に変化が生じた原因は考えることは出来ない、という環境を作ることが学習には適している、と俺は結論付けた。

比較で調べる

f:id:kagamihoge:20030818151859j:plain
その変更以外に原因が考えられない環境とは、つまり比較検証によって実現する。Oracleインストール直後のマッサラ状態と、何らかの変更を施したOracleと、それぞれにおいて、速度確認用のJavaプログラムやSQLを実行する。「何らかの変更」以外は同一でなければならない。こうすれば「何らかの変更」以外に影響を与えたものは無い、ことになる。これがなんで嬉しいかというと、かなり純粋な形で「何らかの変更」が引き起こすこと、を学ぶことが出来る。

Javaプログラム、SQLと実行計画、テーブル構成、インデックスの有無、データ量、行順序、初期化パラメータなどなど……厳密に言えば、物理的に異なる二つのマシンにOracleのデータベースを入れたいところだが、そこはまぁ省略して良いと思う。余りにも厳密さを追求すると今度は前に進めなくなってしまうので、どうせ個人学習が目的なんだし~と割り切ってテキトーなとこで妥協する。

その比較検証によって何を明らかにしたいのか? を、あらかじめザックリで良いので決めておく。たとえば、どっかでJDBCのsetFetchSizeを変更すれば早くなるって書いてあったから確認する(参考)、範囲スキャンとフルスキャンは検索が何%を越えると有利不利が生じるか?(参考)、表の行順序がインデックス範囲スキャンに与える影響を調べる(参考)、などなど。調べたいことと、それで何が起きそうか、がなんとなく頭に思い浮かべられればそれでオッケー。

Oracleに対する変更Aによって、実行時間は変化するハズである。その根拠として、Bが考えられる……てな感じで、ひとまず文章に出来ればOKである。これをやる目的は、何を学びたいかをハッキリさせておいて、このあとの作業にブレが生じないようすること。

Oracleの勉強していてホントーに思い知ったのだけど、人間はホントーに思い込みに支配されやすい生き物である、ということ。こうすればきっと速くなるハズ、がいつのまにか、速くなるベキ、になっていたりする。誤った作業から誤った結論を学んでしまったら目も当てられない。だから、まずは目的をハッキリさせておく必要がある。
f:id:kagamihoge:20140103171351j:plain

実際にやっちまった体験を示す。INSERT10万件をマルチスレッドで分割 - kagamihogeの日記では、INSERT10万件を1つのOracleセッションまたは複数のOracleセッションで実行したとき、速度差が出るかを比較検証している。そのため、実行時間の測定は全Javaスレッドの起動から終了まで、を測ることになる。しかし、当時の俺は何を思ったか個々のスレッドの実行時間の合計を行ってしまっていた。

このように、比較すべき対象とは何か? がしっかりしてないとおかしな事をやらかす危険性が高まる。

これによる損害は、エントリが(永久に)お蔵入りになったり、やる気を失ったりする。

実行する

目的が作れたら、あとはそれを確かめるべく手を動かしていく。手順やら実際に実行したコードやらをブログにベタッと貼り付けることになる。

Oracleに対するALTER文とか、CREATEに追加パラメータ(PCTFREEとか)が必要であればそれも、インデックスやビューの作成が必要であればそれも同様。

適当な件数のデータを入れるためのSQLPL/SQL、スクリプトがあればそれも載せる。これは、どんなデータをどんな順序で挿入したのか、つまりデータの物理的な格納順序、が重要なケース(参考)もあるため。

Oracleで適当な件数のテストデータつくる - kagamihogeの日記 Oracle勉強していて思い知ったことの一つは、適当な件数のテストデータ作るのが地味にめんどくさいこと。よって、自分が勉強用によく使うSQLなどはまとめることにしたが、こういうのもエントリのネタになる。

速度検証用のSQLJavaのプログラムを作る。これは、目的によって1パターンか2パターン作るかが変わってくる。JDBCのaddBatchとexecuteBatchの頻度変更時の動きをstatspackで見てみる - kagamihogeの日記みたいのであれば、バッチありとバッチなしの2パターンが必要。Oracleのdbms_random.valueで1とmaxの間によるランダムセレクションのばらつきを調べる - kagamihogeの日記みたいのであれば、Javaプログラムは1パターンで試行回数増やしての比較になる。

ここにきてよーやく検証用のプログラムを走らせる。プログラムは、基本的に3回は走らせている。これは、偶然を極力省くため。これは実際に俺が経験したことなんだが、たまたま開発機のウイルス対策ソフトが動いていて実行速度に影響を及ぼしたことがある。他にも、たまたまアップデートが走ってしまったとか、色々なものが考えられる。プログラム1回流すのに数分かかる場合に席外したりすると、なおさら分からなくなる。なので、3回やる。3回もやっとけば明らかにおかしな結果には気付けるでしょう(予防線)

感想とかテキトーに書く

f:id:kagamihoge:20140103173842j:plain
最後に、何を学ぶことができたかをテキトーに書く。書くことなかったら、はやくなった! わーい! で良いと思う。そんだけだと味気ないので、最初に何が起きそうかを予測したことと、実際に起きたこととの差を書く。その次に、実際に起きたことは、何によって引き起こされたのかを考える。これは、インプットであげたような書籍・Oracle Databaseオンライン・ドキュメント 11g リリース2 (11.2)・ネット上の各種文献、などを基にして組み立てる。今回のエントリで変更した内容はほげほげ、そしてOracleアーキテクチャはこうなっている、だからほげほげはOracleにふがふがな影響を与える、よって今回のような結果を生み出す、とかなんとかな感じで書いていく。せっかくのブログなんだし、好きなこと好きなだけ書いて、飽きたらそこで終了にして、アップしてしまうのが良いと思う。

あと、手順やコードをブログに載せるのは、後々自分が振り返ってみるときに分かりやすくしておく意味もあるし、第三者による検証を可能にしておく意味もある。これは人によって意見は割れるかもしれないけど、俺はブログにおかしなこと書いても良いと思ってます。まぁ、なんというか、例えばの話、ぜんぜん知らない人が自分のブログを読んでこれおかしいじゃん? と間違いに気付けるだけの材料がブログに書いてあれば、まだマシといいますか。前提条件マッタク書かずに「これやるとOracle速くなる!」とか書くよりかは誠実なんじゃないかなぁ、と思ってます。

仮説と検証

といったわけで、俺がどのようにOracleを勉強してきたかを一言で表現すれば「仮説と検証」となる。まず仮説としてOracleにこんな変更を加えればこんな結果が得られるだろう、というものを立てる。そして、仮説の裏付けをするため実際にOracle上にテーブルやインデックスを作り、データを挿入し、必要なパラメータを書き換え、検証用プログラムを作成して実行する。最後に、仮説を検証すべく得られた結果と各種信頼の置ける文献とを照らし合わせて考察を行う。そこから新たな疑問が生まれればそれを解消するために同様に「仮説と検証」のルーチンを繰り返す。無ければインプットを増やして新たなネタを探し、再び「仮説と検証」のルーチンを繰り返す。

堅苦しく書けばこうなるが、ぶっちゃけやってることは情報系でよく課されるレポート「バブルソートクイックソートを実装しその差について考察せよ」と変わらない。異なるのは、自分で問題を設定し、自分で評価を行うことだけども。

自分が知りたいこととピッタシ重なる上に難易度も程よい教材とか講義みたいのが転がっているとか周囲に詳しい人がいるとかなら、こんな回りくどい勉強法は取らなくても良かったのかもしれない。それに、このエントリ書いてる段階では何が知りたいのか概ねハッキリしてきたけど、最初のうちは何を勉強したらいいのかも良くわかっていなかった。となると、自然に発見的なアプローチを取るようになり、気付いたら大学でしこたまやった学習スタイルを取るようになっていた。

効率的なやり方だった自信は無いけれど、学部生の頃散々仕込まれた学習方法をごく自然に取っていたことが俺には面白かった。大学を卒業するとき、研究室の担当教授が「大学で何学んだかは忘れてもいいけど、自分なりの勉強のやり方が分かってればそれで良いよ」と言っていたのが思い出される。

さいご

まぁなんちゅーか、データベースの勉強も悪くないもんです。

*1:ちなみに、レスポンスタイム・スループットの違いはあまり区別せずにやっていた