【IRIS】【SQL】並列クエリについて

はじめに

クエリの実行速度を調査していた際、2つのクエリの速度差に違和感を覚え、原因を調査しましたた。
その際に、「並列クエリ」を学ぶ機会があり、今回の記事のネタにしました。

下記に該当する方を対象として解説を行いたいと思います。

  • InterSystems IRIS製品をご利用の方(Cacheは並列クエリを利用できません)
  • IRISの並列クエリが初耳の方
  • クエリの実行速度を向上させたい事
  • IRISを動作している際、CPUの高騰する原因を調査している方

並列クエリとは何か

その名の通り、「複数のプロセッサを搭載したのコンピュータシステム」環境で動作させている場合、1つのクエリを複数のプロセスで同時(並列)に実行する事を指します。

1つのクエリを分割して実行するので処理速度は向上しますが、引き換えにCPUの負荷が上昇します。
処理速度とCPU負荷のトレードオフですね。

ただし、並列クエリは全てのクエリが対象ではありません。
並列処理が出来るクエリ・出来ないクエリがあります。

また、自動的に並列クエリとしてクエリが実行されるケースと、任意の設定によって並列クエリを実行させるケースがあります。

今回は、ここら辺を深掘りしていこうかと思います。

並列クエリの自動設定

管理ポータル起動後、[システム管理] > [構成] > [SQLとオブジェクトの設定] > [SQL]を開きます。

画面「SQL」で、「単一プロセス内でクエリを実行」にチェックが付いていない場合、SQLオプティマイザの判断によって、自動的に並列クエリが選択されます。

※この設定は、IRIS 2019.1より実施されています。

SQLオプティマイザ

クエリを解析し、適切なクエリ・キャッシュを作成する。
インデックス使用の選択等を行ったり、クエリ内容をM言語に翻訳する係と思われます。

オプティマイザが「並列クエリで行くぞ!」と判断したクエリ

並列クエリの任意設定

並列クエリの自動設定を行っていても、全てのクエリに対し並列で実行するわけではありません。

大まかに下記条件に該当するクエリは、並列クエリの対象外となります。

並列クエリ対象外の条件
  • select文以外の「insert文, delete文, update文」
  • INSERTコマンド・サブクエリ
  • TOP節とORDER BY節を両方含むクエリ
  • ビューを参照し、ビューIDを返すクエリ

一部抜粋。詳しくは下記参照

・クエリ並行処理の無視

一先ず、並列クエリ対象外の条件が分かったので、次は任意で並列クエリを設定してみましょう。

通常のクエリ ※参考比較用 

先ずは、並列クエリが実行されないクエリのプランになります。

並列クエリ(%Parallelキーワード付与)

並列クエリを実行するには、FROM節の直後に「%Parallel」と記載します。
クエリプランを確認すると、「Call module A in parallel on each subrange, piping results into temp-file B.(各サブ範囲でモジュール A を並列に呼び出し、結果を一時ファイル B にパイプします。)」との一文が含まれています。

並列クエリ実行

下記結果は、先ほどのクエリを実行した時の処理速度を比較しています。
処理速度の比較だけで見ると、並列クエリを使った方が圧倒的にお勧めできる設定だと思います。

項目1回2回3回4回5回6回7回8回9回10回平均
並列30.1731.9331.3032.0131.6832.2130.5031.7731.9331.6331.51
通常94.6487.4986.4489.1689.8386.7386.1787.2586.4382.8087.69
並列クエリと通常クエリの処理速度比較

では、このときのCPUの負荷はどうなっているでしょうか。
タスクマネージャより、CPUの負荷を確認してみます。

■並列クエリ時のCPU負荷

■通常時のCPU負荷

並列クエリを実行すると、天井を「ド衝く」勢いで高騰しているのが分かります。
その代わり、処理がすぐ終わっているのが確認出来ますね。

一方の通常のクエリでは、CPUの高騰こそないものの、処理の終了がかなり長い時間かかっているのが分かります。
つまり、その間ずっと1つのCPを占有していることになります。

CPU爆上げでの短期決戦か、CPUの上昇を抑えての長期決戦か・・・
両極端ですねぇ。
並列クエリで稼働させるプロセス数を制御できれば、並列クエリ一択かもしれません(笑

並列クエリを使いたくない時

並列クエリを何らかの理由で停止したい時の対応方法になります。
全体を根っこから停止させる方法と、個別に停止させる方法があります。

根っこから停止させる

管理ポータルの画面「SQL」で「単一プロセス内でクエリを実行」にチェックを入れる方法と、下記コマンドを使用することでも、システム全体での使用を停止する事が可能です。

// 1が既定値で「並列処理有効」
s sts = $SYSTEM.SQL.Util.SetOption("AutoParallel",0,.oldval)

※いずれにしても「%Parallel」キーワードが付与されたクエリは止まりません。

設定値の確認を行うには、下記コマンドを実行します。

d $SYSTEM.SQL.CurrentSettings()

実行結果は下記になります。
16行目「Enable auto hinting for %PARALLEL」が「0」になっている事が分かります。

SQL CONFIGURATION SETTINGS
  SQL OPTIONS
    Retain SQL as comments:                       1
    ECP sync for SELECT statements:               0 (Default)
    Cached query save source flag:                1
    Identifier translation from:                  ~ `!@#$%^&*()_+-=[]\{}|;':",./<>? (Default)
    Identifier translation to:                     (Default)
    Default time precision:                       0 (Default)
    TCP keep alive interval (in seconds):         300
    All class queries project as stored procs:    0 (Default)
    Lock escalation threshold:                    1000 (Default)
    Default schema:                               SQLUser (Default)
    Support delimited identifiers:                1 (Default)
    Allow extrinsic functions in SQL statements:  0 (Default)
    Apply ANSI operator precedence :              1
    Enable auto hinting for %PARALLEL :           0
    Threshold of auto hinting for %PARALLEL :     3200 (Default)
    Enable RTPC :                                 1 (Default)
    Enable adaptive mode :                        1 (Default)
    Enable parameter sampling :                   0 (Default)
    Lock timeout:                                 10 (Default)
    SQL security enabled:                         1 (Default)
    Perform referential integrity checks on
     foreign keys for INSERT, UPDATE, and DELETE: 1 (Default)
     ODBC VARCHAR Max Length:                     4096 (Default)
     TO_DATE() Default Format:                    DD MON YYYY (Default)
  DDL OPTIONS
    Allow DDL DROP of non-existent table or view: 0 (Default)
    Allow DDL CREATE TABLE or CREATE VIEW
     for existing table or view:                  0 (Default)
    Allow create primary key through DDL
     when key exists:                             0 (Default)
    Allow DDL DROP of non-existent constraint:    0 (Default)
    Allow DDL CREATE INDEX for existing index:    0 (Default)
    Allow DDL DROP of non-existent index:         0 (Default)
    Allow DDL ADD foreign key constraint
     when foreign key exists:                     0 (Default)
    Does DDL DROP TABLE delete the table's data?: 1 (Default)
    Are primary keys created through
     DDL not ID keys:                             1 (Default)
    Are classes created via DDL
     CREATE TABLE statement defined as Final:     1 (Default)
    Do classes created by a DDL CREATE TABLE
     statement use $Sequence for ID assignment:   1 (Default)
    Do classes created by a DDL CREATE TABLE
     statement define a bitmap extent index:      1 (Default)
  SQL OPTIMIZATION OPTIONS
    DISTINCT optimization turned on:              1 (Default)
    Bias queries as outlier:                      0 (Default)
    %ALLINDEX optimization turned on:             0 (Default)
    %NOFLATTEN optimization turned on:            0 (Default)
    %NOMERGE optimization turned on:              0 (Default)
    %NOSVSO optimization turned on:               0 (Default)
    %NOUNIONOROPT optimization turned on:         0 (Default)
    %NOTOPOPT optimization turned on:             0 (Default)
  RELATIONAL SERVER OPTIONS
    Server Initialization Code:                   (NONE) (Default)
    Server Disconnect Code:                       (NONE) (Default)

ただ、根っこから止めてしまうと、他の自動で動作していた並列クエリまで止まってしまうので、よく検討してから実施して下さい。

個別に停止させる

オプティマイザーが並列クエリを実施すると判断したクエリに対し、並列クエリの実行を停止する方法は「%noParallel」キーワードをクエリに付与します。

下記クエリの様に、from節の直後に「%noParallel」キーワードを付与します。

select 性別 from %noParallel developer_data.Patient2 group by 性別

おわりに

今回は並列クエリの解説でした。

並列クエリは、既存のロジックを変更しなくても、容易に速度を向上させる事が可能です。
 ※インデックスの新規追加・変更、クエリの変更等々

ただ引き換えとして、CPUが高騰する可能性が高いです。
並列クエリの設定は、計画的に行った方が良いですね。