'Active Query Index Hints' を使用して遅いクエリの実行を改善する方法Issue 「アクティブ クエリ インデックス ヒント」を使用して遅いクエリ実行を改善する | パフォーマンスの改善 目的 この記事は、ServiceNow にアクティブクエリインデックスヒントを追加するタイミングと方法を明確に説明する目的で作成されました。 対象者 MySQL データベースを使用している ServiceNow セルフホストのお客様と、データベースオプティマイザーで選択された実行計画が最適でない場合にクエリの改善を必要とする ServiceNow テクニカルサポートエンジニア。 警告:ServiceNow によってホストされているお客様は、この情報を一般的な知識として参照することはできますが、以下に示す手順の多くを実行することはできません。ホストされている環境内でクエリのパフォーマンスが遅い場合は、ServiceNow サポートでケースを作成することを強くお勧めします。 トピック 時間のかかるクエリを特定するDB の遅さを確認するインデックス候補を判定するExplain Plan を取得する既存のインデックスを比較するインデックスヒントで改善をテストするアクティブクエリインデックスヒントのフォームを設定するクエリーヒントを定義する改善を確認する 時間のかかるクエリを特定する: バックグラウンド: 一部のユーザーがホームページの表示が遅いことに不満を抱いており、以下のように、低速クエリ(Slow Queries)モジュールを使用して、ホームページからのクエリが遅いことを特定しています。 ヒント: ターゲットにしているクエリの影響が大きく最適化が必要であることを確認するために、平均実行時間 > 2000 ミリ秒、実行数 > 500 と表示されるフィルターオプションを検討してください。そうすると、サンプルの Java スタックトレースが Default-thread で始まります。つまり、対話型ユーザートランザクションとなります。リストを [合計実行時間] で並べ替えると、最も重要なクエリが最初に表示されます。 ターゲットクエリを開き、[前回の発生 (Last sighting)] フィールドを見て、クエリが引き続きパフォーマンスに影響を与えていて改善が必要であることを確認します。[例] フィールドの SQL をコピーし、任意のシンプルなテキストエディターに保存します。MS Word やその他のリッチエディターは使用しないでください。 DB の遅さを確認する 問題のインスタンスに使用されている MySQL データベースにアクセスし、同じ SQL クエリ (上からコピーしたもの) を実行して、クエリが遅いことを確認します。 インデックス候補を判定する: 上記 SQL の where 句を見ると、次のタスクテーブル内の列の複合インデックスが適しているように思われます。 assignment_groupstateassigned_to これは現時点では単なる推測に過ぎませんが、現在使用されているインデックスがある場合は、それを確認してください。 Explain Plan を取得する: MySQL の Explain Plan メカニズムを使用して、SQL クエリがアクセスする必要のある行数および使用されているインデックスを確認します。 インデックスが使用されている間 (task_ref2) も引き続き 200 万行へのアクセスが行われ、結果として返されるのが 0 行であることに注意してください。データベースでこれを行うには 5.5 秒かかります。 既存のインデックスを比較する: task_ref2 インデックスがタスクテーブルのどの列から作成されたのかを確認します。 注:MySQL バージョン 5.6 のテーブルでは、インデックス数が合計 64 個までに制限されています。この例では、タスクテーブルにすでに 62 個のインデックスがあります。インデックスには複合 (複数列) のものも単一列のものもありますが、合わせて 64 個という制限を超えることはできません。 ターゲットテーブルのインデックス数がすでに許容可能な最大値に近い場合は、より適切な既存のインデックスを探してください。 タスクテーブル内の既存のインデックス付き列を確認すると、より適切と思われる where 句からの 3 列すべてをカバーする既存のインデックスがあります。現在使用しているインデックス task_ref2 on では assigned_to 列しかカバーされていません。このインデックスは、上で示すようにアクティブになっています。 where 句に基づくインデックス候補が次に示す列の複合インデックスである可能性があることは、すでに言及しました。 assignment_groupstateassigned_to インデックス作成が役に立つと思われる 3 列すべてを提供する既存の複合インデックスがあります。 インデックスヒントで改善をテストする: より適切と思われるインデックスがすでに存在していることがわかったので、強制インデックスクエリヒントを使用して、クエリの速度が上がるかどうかを確認します。 以前は、データベースオプティマイザーが最適と考えるインデックスを使用してこの同じクエリを行うのに 5.5 秒かかっていました。この新しく見つかった複合インデックスを使用すると、頻繁に使用されるこのクエリのクエリ時間が約 4 秒短縮されます。これは大きな改善です。このケースでは、クエリヒントがパフォーマンス改善に役立つのは明らかです。 注:OR 条件が複数あり IS NULL があることを考えると、このクエリは理想的ではありません。多くの場合、数種類の既存のインデックスを注意深く評価して試し、改善が見られない場合はクエリ自体を評価して書き直すことが必要になります。無視インデックスクエリヒントが強制ヒント以上に役立つ場合もあります。テストは、適切なソリューションを見つけるための鍵です。 アクティブクエリインデックスヒントのフォームを設定する (必要な場合): 注:PRB1439443 - アクティブクエリインデックスヒントは、エイリアスが切り詰められているテーブルでは機能しません。たとえば、x_nuvo_facilities_work_order という論理名を持つ x_nuvo_f8s_work_order という名の物理テーブルは、インデックス ヒントを受け取ることができません。ワークアラウンドとして、アクティブクエリの書き換えを使用できます。 既存のインデックスがクエリ実行速度向上に役立つことを確認したので、ServiceNow インスタンス内にアクティブクエリインデックスヒントを作成できます。これまでの作業はすべて、クエリ実行を高速化する方法を探すために行ってきました。ここからは、プラットフォームに修正策を実装します。 フィルターナビゲーターに「Active Query Index Hints」と入力し、[新規 (New)] ボタンをクリックします。ページが以下のようにほぼ真っ黒に見える場合は、設定する必要があります。フォームにほかのフィールドもある場合は、次のセクションが表示されるまで下方向にスクロールします。 注:セルフホストのお客様の場合、このアクティブクエリインデックスヒントモジュールにアクセスするには、ServiceNow にメンテナンスユーザー認証情報を要求する必要があります。 必要なフォームフィールドを追加するには、次の手順を実行します。 [設定 (Configure)] > [フォームレイアウト] に移動します。選択された次のフィールドを追加します。 上で行ったフォームレイアウト変更を保存すると、空のフォームの表示が次のようになります。 アクティブクエリインデックスヒントを定義する: スロークエリモジュールから、最も低速かつ最も頻度の高いクエリ (/home.do 呼び出し) を特定し、これを改善のターゲットとしました。そして、インデックスヒントを強制するとクエリの実行時間が大幅に改善されることがわかりました。今度は、アクティブクエリインデックスヒントを定義します。 次の例のように、サンプル (ターゲット) クエリ、テーブル名、ヒントタイプ、インデックス名、および相関名を入力します。次の点に注意してください。 上で黄色く強調表示されている領域は、名前ではなく、列ごとによる結果としての強制ヒントを示しています。これはフォームの奇異な側面ではありますが、想定どおりに動作するはずです。保存すると、インデックスヒント例にインデックス名が表示されます。以下を参照してください。インデックス名選択ポップアップにはインデックス名で検索するオプションがありますが、選択すると列が表示されます。相関名は、クエリ自体からのテーブルエイリアスです。 テーブル名、ヒントタイプ、アクティブフラグ、およびその他の詳細を入力したら、ヒントを保存または送信します。検証プロセスが実行され、保存が成功すると、次のような青字の成功メッセージが表示されます。書き換え SQL の例 (上で赤く表示) を、データベースで以前にテストしたものと比較します。 注:スペース、特殊文字のコピーアンドペースト、埋め込みキャリッジリターンはすべて注意が必要であり、プラットフォームクエリヒントが適切に実装されない原因になる可能性があります。サンプルクエリに余分なスペースがある場合はスペースを維持する必要があります。クエリヒントも同じである必要があります。シンプルなテキストエディターが最良と言えるのは、誤って特殊文字がヒントに挿入されることがないためです。 改善を確認する: ターゲットの SQL 実行時間の改善は、いくつかの方法で確認できます。 クエリのソースがわかっている (たとえば、ページ上の特定のフィルター、レポート、ウィジェットなど) 場合は、[SQL のデバッグ (詳細)] を有効にして、元のバージョンのクエリから上記の強制インデックスヒントで定義したものに正しく置き換わっていることを確認できます。 この記事の冒頭にある元のクエリから、ソースが /home.do 呼び出しであったことがわかっています。この場合、ユーザーのホームページとウィジェットがわかっており、デバッグ出力を介してプラットフォームがクエリを適切に置き換えていることをすばやく確認できます。以前の定義インデックスヒントを非アクティブに設定する (またはインデックスヒントより前に直接検証する) ことで、元のタイミングをすぐに利用できます クエリのソースが明確でない場合は、ターゲットクエリを特定するために当初使用したのと同じパラメーターを使用して Slow Query モジュールを監視し、 [前回の発生] にインデックスクエリ ヒントより前の時間が表示されていることを確認できます。スロークエリモジュール内で適切なフィルター条件を使用すると、直近の [前回の発生] タイムスタンプで新しい強制インデックスクエリも表示されます。次の例は、強制インデックスヒントが表示されているクエリの元バージョンと新バージョンを示しています。 注:無視(ignore)、強制(force)、および使用(use)の各ヒントタイプにも、これと同じ検証およびヒント作成プロセスを使用できます。この注意書きは、それぞれに同等に適用できます。