前回は、CPUボトルネックを解消するアプローチとして「並列化」および「リソース・マネジメント」をご紹介しました。今回は、それらをOracle Database上で実装する方法についてご紹介します。環境はOracle Database 11gR2を想定しています。
処理を並列化する2つの手法
Oracle Database上のSQL処理を並列化するには、2つの手法があります。
1.アプリケーション側でSQLを分割して同時実行する
Oracle Databaseでは、1セッションあたり1つのサーバ・プロセスが立ち上がります。複数セッションから複数のSQLを同時に実行すれば、複数のOSプロセスが処理を行うので、複数のCPUコアが利用されます。
この手法は、SQLを分割する手間がありますが、大規模バッチでは有効です。
2.Oracle Databaseの並列化機能を利用する
大規模データを参照する場合、ユーザからのリクエストに応じて、そのつどアプリケーション側でSQLを分割実行することは現実的ではありません。そういった場合に役立つのが、Oracle側でSQL文を並列処理する機能です。
具体的には以下の2つを利用するのがおすすめです。
- パラレル・クエリ(以下、PQ)⇒ SELECT文を並列処理する
- パラレルDML(以下、PDML)⇒ INSERTやUPDATEなどの更新SQLを並列処理する
これらを利用すると、図のように処理が複数のスレーブ・プロセスに分けて実行され、複数のCPUコアが利用されます。
パラレル・クエリとパラレルDMLを利用するには
PQとPDMLの利用方法を見てみましょう。
パラレル・クエリの利用法
PQを利用する方法は、以下の表のように複数あります。
表1 パラレル・クエリの利用方法
手法 | 利用方法 | 有効範囲 |
SQLヒント | SQL> SELECT /*+ PARALLEL(<並列度>) */<残りのクエリ>; | ヒント指定したSQLのみ |
ALTER SESSION | SQL> ALTER SESSION FORCE PARALLEL QUERY PARALLEL <並列度>; | 当該セッションのすべてのSQL |
表属性 | SQL> ALTER TABLE <表名> PARALLEL <並列度>; | 当該表にアクセスするすべてのSQL |
まずは改善したいSQLにヒント文を追加して、PQによる改善が見られるかを確認しましょう。
その後、類似したSQLでも試してみて、効果があった場合、その対象を広げてみましょう。たとえば、同一セッションで複数の類似SQLが実行されるバッチ処理であれば、セッション単位での設定を試すべきです。
特定の大規模表にアクセスするSQLが多いのであれば、表単位で設定するのが有効です。
パラレルDMLの利用法
PDMLを利用するには、SQLヒントにて並列度を指定するやり方が一般的です。その際、注意点が2つあります。
まず、SQL実行前に、以下を実行してください。
また、PDML完了時に、明示的にCOMMITまたはROLLBACKにて、トランザクションを完了させる必要があります。
並列化で問題になる4つのこと
並列化は、うまくいけば改善効果も大きいため、皆さん喜んで実施しますが、必ずしもいいことばかりがあるわけではありません。以下の4つの点に注意しなければなりません。
1.並列化するオーバーヘッドのほうが高くなる
1秒未満で終わるような「元々速いSQL」を並列化しても、複数プロセスに処理を分割するオーバーヘッドのほうが高くなり、期待したほどの効果は得られません。
2.PQ実行時に性能が劣化する
PQ実行時は、実行計画でHASH JOINが選択されることが多くなります。適切なパーティション化、結合条件がない場合、大量のハッシュメモリが利用されて、一時表領域にデータがあふれ、性能が劣化するケースがあります。
3.ディスクI/Oボトルネックが復活する
並列化すれば、同時に実行されるI/O命令数も増えますので、ディスクI/Oボトルネックが復活する可能性があります。
通常の外部ストレージを利用している環境では、並列処理に耐えられるよう、ストレージ装置側やネットワークの回線状況もあわせて確認する必要があるでしょう。その際には、スループットを重視した改善を検討してください。
なお、Oracle Exadataであれば、第3回でご紹介したとおり、大規模並列実行時もI/Oボトルネックを生じさせにくいアーキテクチャとなっているので、こういった問題は起こりにくくなります。
4.CPUのリソースが不足する
並列化が進むと、今度はCPUリソースが足りなくなり、歯止めが効かなくなることが多くなります。
機能を利用して効率的なリソース・マネジメントを
並列化の問題をフォローし、インフラ側でRDBMSを守り、はたまた自分の身を守るためにマスターしておくべきなのが、「リソース・マネジメント」です。
CPUボトルネックは、複数の処理がCPUリソースを奪い合うことで発生します。この奪い合いを抑制するのがリソース・マネジメントです。
これには2つの手法があります。
1つめは、処理ごとに、リソースをOSレベルから分けてしまうのは強力なアプローチです。たとえば仮想化環境を利用している場合、DBごとに仮想マシンを分割し、CPU割当数を調整します。ただし、DBを分割してしまうと業務に影響がありますし、個別管理するOS/DBが増えて運用上の手間となります。
そこで利用したいのが、Oracleの機能で、処理が利用できるCPUリソース量を外部から制限する方法です。
Oracle側でのリソース制限の基本的なアプローチは「出る杭を打つべし」です。特定リソースをたくさん利用しているセッションを強制的に待機させることで、CPU使用率を制限させます。すべてDB内部で透過的に行われ、無駄も少なく、効率的です。
ケースごとに最適な機能を使う
Oracleのリソース・マネジメント機能にはさまざまなものがあります。以下のように、場合に応じて最適なものを利用してください。
同一OS上で複数のデータベース・インスタンスが稼働している場合
インスタンス・ケージング機能が有効です。DB初期化パラメータのみで設定できるので、ぜひ活用してください。
同一DB上で複数処理が相乗りする場合
DB側のリソース・マネージャ機能(DBRM)を利用しましょう。Enterprise Manager(EM)の画面から実施すると、とてもかんたんに設定できます。なお本機能は、OS側のCPU使用率が100%になった場合に発動し、セッション間のCPUリソース使用量を制限します。
Exadataを利用している場合
Exadata限定の機能、I/O Resource Manager(IORM)を利用しましょう。さまざまな単位でディスクI/Oのスループットを制限することができます。たとえば、夜間にバックアップを取得する場合に増えるディスクI/O負荷が、バッチなどの業務処理に影響しないように設定できます。
前回(第4回)と今回(第5回)で、CPUボトルネックにまつわる解説は終わりです。次回からはネットワークI/Oのボトルネックについて説明しますのでお楽しみに!