パラレル化で複数CPUコアを駆使

柴田長氏:続いていきましょう。

「パラレル化で複数CPUコアを使いこなせ!」、ミッション3です。先ほどパーティション化したCPUバウンドのSQLのアクティビティを見きました。8つのCPUコアがありますが、どうしても1CPUコアのボトルネックになっていました。これ、もったいないですよね。

なぜ起きるかと言うと、SQLの実行ではCPUコアが1つしか使えません。なぜならば、クライアントからSQLが投げられるとOracleのInstance上ではSever Processが1人だけフォークされます。

その1つのプロセスが全データを読み取って演算処理を行うので、1つのプロセスしかないわけです。そのため、1つのCPUしか使えないです。これはもったいない。

これを解決するのが、みなさんご存知だと思いますが、パラレル実行がありますね。これはクライアントからSQLが投げられると、Query Coordinatorというプロセスが、コーディネータープロセスが1つ立ち上がります。

その下に子分、Parallel Execution ServersというPROCESS文が起動しますので、子分たちが実際にデータを読んで演算処理をする。こういうことができますので、1つのSQLで、SQL文を書き換えることなく、複数のCPUコアを同時に使うことができます。

おもしろいのは、下のTableですね。重複して読まないんですよ。子どもたちのプロセスたちは同じデータを一切読みません。これはパーティション化していない表であっても、きれいに分割して子分たちが読みます。

なので、パラレルクエリを使うことによってデータの読み込み量が増えるといったことは絶対にないです。これは安心してください。

パラレルクエリを実施

では実際にどうやってパラレルクエリを使うのか。どうやってパラレル実行を使うのか。本日は2つの方法をご紹介しましょう。

1つは、手動です。手動で強制的にパラレルの指示が、「alter session force parallel query parallel n」です。このnには数字を書きます。パラレル度ですね。これをSELECT文を実行する前に1発打つ。これだけですね。そうすると、そのあとで実行するSELECT文がパラレル化する。

もう1つは、パラレル度をいくつにしたらいいかがわからない場合には、自動パラレル度設定があります。これはOracle Database Instanceの初期化パラメータPARALLEL_DEGREE_POLICYといったパラメータがありますので、これがデフォルトのマニュアルです。

無効になっています。これをLIMITED,AUTO,ADAPTIVEという3つのどれかに変更することで、1度パラレル設定が有効化していきます。

それによって実際に大量のデータを読む。パラレル化したほうがいいとOracle Database自身が判断した場合にパラレル化される機能があります。小さいデータなのでパラレル化しないほうがいい場合にはパラレル化されません。Oracle Databaseに完全に任せるのが画面の下ですね。

ほかにもパラレル関連のパラメータはホワイトペーパーにも記載がありますので、ぜひ参考にしてみてくださいね。

実際に、今回は手動で一気にやっちゃいましょう。alter session force parallel query parallel と打ちます。1コアしかないんですけども、ハイパースレッドオンなので、16にしてみましょう。16にして、@query_CPUでポンと打つ。これだけ!

これでもうパラレルクエリが動いているんですね。SQLは変えていません。本当かと不安な方はEnterprise Managerです。Enterprise ManagerでどんなSQLが今流れているのかと見ると、流れています。実行されています。

1CPUコアボトルネックを突破

パラレル化されているかどうかは、この一覧でパラレルという列で16と入っています。先ほどalter sessionでパラレル16と強制したので、今、このSELECT文はパラレルで動いています。

SQL文はcq2ですよね。CPUバウンドです。なんと、もともと1.1分かかっていたものが19秒で終わるようなことが起きます! すごいですね。

本当かどうか見てみましょう。実行時間が19秒。データベース時間が19秒ではなくなっています。これは19秒のうちに、たくさんの子分が動いたので、その累積がデータベース時間になっていますね。

IOバイト数6ギガバイトで変わってないです。パラレル化してもI/O量が変わらない、増えないと最初に私が言った通り、変わっていません。

では1CPUコアボトルネックだったのか。これはどう変わったのか。小さくて見えないですけども、緑色がCPU使ったところです。同時にハイパースレッド込みの16ギガバイトを使っている傾向が見えます。

なので1CPUコアボトルネックを突破して、壁を突破して複数CPUを同時に使ったことをこの画面からも見てとれると思います。

パラレルクエリの効果と恩恵

もう1つ、I/Oバウンドもあります。これも@query_IOと投げます。こちらはもともとI/Oがボトルネックの状態です。いくら複数のCPUを同時に使えたとしても、I/Oがボトルネックですから、ほとんど改善しません。

所要時間が72秒から20秒になりました。CPUバウンドで1CPUコアがボトルネックでしたからね。パラレルクエリの効果恩恵が非常に高かったです。こういう状態だったのが、CPUが緑色のところが増えました。

ただ、暗い緑色というかブルーありますよね。これがI/O待ちです。I/O待機を示していますので、この時間がまだまだ長いのがここから見てとれます。

I/Oバウンドは、実際にデモではお見せしていませんでしたけども、あまり変わりません。20秒です。こんな感じでほぼI/Oバウンドのほうが今回のSQLはパラレルの効果がない。そのため、SQLによって機能に効果があったりなかったりします。それを少しお見せしたかったのです。

なぜならば、ここにある通り、データベース時間の青いところはユーザーI/Oの待機時間が多い。つまりユーザーI/Oがボトルネック。複数CPUを使いこなすことはできません。

CPUバウンドのSQLは20秒まで、5.4倍まで高速化しました。

データ圧縮でI/O量をより削減

続いてのライブチャレンジいきましょう。

次のミッション4は、「データ圧縮でさらなるI/O量の削減を狙え!」です。CPUバウンドのSQLもI/OバウンドのSQLもどちらも、まだまだIO待機時間が長かったですよね。それをなんとかしたい。そこで登場するのが、表圧縮機能になります。

Oracle Databaseはいくつかの表圧縮の方法をサポートしています。圧縮というと、どうしてもディスクスペースを節約する話になります。今回はそうではないです。今回はパフォーマンス観点で圧縮が効く話をしたいです。

圧縮すると、Oracleのレコードを管理しているデータブロック……例えば1つのブロックの中に10レコードしか入らなかったもの圧縮すると30レコード入るんですよね。

つまり3倍圧縮されていますから、I/Oする回数が3分の1で済みます。そういうことが圧縮で行われます。そのため、総ディスクI/O回数が削減してディスク待機時間が減ります。

もう1つ、今回は関係ないですけども、キャッシュヒット率が向上します。なぜならば、左側の絵でまず非圧縮の表をOracle Database 、DBサーバ側に読みこみます。そこでI/Oがボトルネックになってしまうという図です。

I/Oがボトルネックということは、DBサーバ側のCPUで演算処理しているデータが届かないので、CPUが使えません。待っている状態なんです。メーターがぜんぜん回ってない状態です。

一方、圧縮してしまえば、ディスクI/O時間が短いです。圧縮されたままDBサーバのメモリ上に持ってきます。その上で展開しますから、ディスクI/O時間は短いです。もう手元にデータがすぐ来ますから、CPUをブン回すことができるということで、メーターが回っている。そんなイメージですね。

データ圧縮の方法

圧縮の方法はたくさんあるんですよ。小さいですけども、マニュアルの抜粋です。基本圧縮、高度な行圧縮、ウェアハウス圧縮、アーカイブ圧縮。たくさんあるんですけども、本日はこの赤いところで印を付けた高度な行圧縮をお見せしましょう。

これはなぜかと言うと、圧縮レベルが高いです。CPUオーバーヘッドが低いです。向いているアプリケーションはOLTPとDSS、Decision Support System。だからデータウェアハウス系ですね。どちらにも向いている圧縮形式がありますので、こちらを使ってみましょう。

実際にこれは圧縮しましょう。ただコマンドはそんな難しくはないんですが、「@Enable_Compression」と打っていきます。

alter table SALESのmove partition、あるpartitionをrow store compress advancedという圧縮形式に変えます。しかもonlineで、という句を付けています。

少しご紹介しますね。圧縮表はもともと、初めて表を作るケースでCREATE TABLEと打ちます。その際にrow store compress advancedと付けていただければ、高度な行圧縮、表圧縮が有効な表を作れます。もともと表があり、データが入っている場合には2種類の方法があります。

今後、INSERTされてくる新規のデータのみを圧縮する場合には、その表の属性を変えるのでalter table modify partition compress。partitionと書いているのは、今回は表全体ではなくて、パーティションで紹介したある特定の分割された部分、ある部分だけを圧縮することができますので、参考に書いています。

すみません、脱線しました。もう1つは、既存の格納されている表の中に入っているレコードも含めて圧縮したい場合には、alter table move partition compress ~と書いていただければいいです。

さらに、ここにonlineという句を付ければ、圧縮中にも更新処理アップデート、インサート、デリート処理を受け付けられるようになっています。これも12cの機能ですね。これは便利です。

もともと表のオンライン再定義という、一番下に小さく書いてあり、これを使ってもできます。コマンド一発でできるonline句は非常に便利ですから、使ってみてください。