SQL Server のインデックスと、選択のパフォーマンスの利点と更新/挿入の欠点についていくつか読んだ後、不適切に使用されたインデックスが実際に選択のパフォーマンスを損なう可能性があるかどうか疑問に思いました。インデックスが純粋な選択クエリのパフォーマンスを低下させるには、どのような条件を満たす必要がありますか? そのような状況は存在しますか?
ありがとう!
(私は常にコード例を含めようとしていますが、この質問をサポートするものは何も考えられません...)
SQL Server のインデックスと、選択のパフォーマンスの利点と更新/挿入の欠点についていくつか読んだ後、不適切に使用されたインデックスが実際に選択のパフォーマンスを損なう可能性があるかどうか疑問に思いました。インデックスが純粋な選択クエリのパフォーマンスを低下させるには、どのような条件を満たす必要がありますか? そのような状況は存在しますか?
ありがとう!
(私は常にコード例を含めようとしていますが、この質問をサポートするものは何も考えられません...)
はい、ごくわずかではありますが、「いいえ」と答えるのも正当化されるほどわずかです。
クエリの対象となる可能性があるが使用できないインデックスがある場合、オプティマイザーはそれを使用するかどうか、および使用する方法を検討するために短時間の時間を無駄にします (まれに、非常に複雑なインデックスとビューを使用する場合や、インデックスのパフォーマンスのヒントが得られる場合に頻繁に発生します)。最適でないクエリ プランを選択する可能性があります)。
いくつかのケースは次のとおりです。
最初の 2 つのケースではクエリ時間は同じですが (フル スキャンが必要です)、3 番目のケースでは、インデックスを分析して破棄する必要もあります。可能性は低いが可能性のある 4 番目のケースでは、おそらく非常に大きな実行時間が増加し、巨大になります (2021 年 10 月 20 日更新:私は自分自身でこれを実行しました. やったー)。
インデックスがあなたを傷つける可能性が高い場所 - すべてのインデックスがあなたを傷つける場所 - は、挿入、削除、および更新です。次に、更新クエリで使用されていないが、更新クエリの影響を受けるインデックスは、インデックス自体への書き込みが必要になります。
したがって、SELECT のパフォーマンスを犠牲にしない限り、インデックスはできるだけ少なくしたいと思うでしょう。実際には、必要なインデックスが他のすべての UPDATE クエリによって常に更新されるのを避けるために、めったに使用されない SELECT クエリのインデックスを作成しないことにするかもしれません。
編集: Heinzi の回答を読んだ後、ほとんどの DB サーバーには、テーブルとインデックス (および場合によってはクエリ パフォーマンス カウンターも) を分析するメンテナンス ツールがあり、Heinzi が話したヒントを適切に更新することも追加したいと思います。そのため、データベースを定期的に「維持」して、オプティマイザに選択するインデックスに関する最新の情報を提供し続けることも重要です。
既存のインデックス作成の改善 (未使用のキーの削除、有用なキーの追加) を実際に提案できる非常に気の利いた MySQL 分析ツールがあります: common_schema。一見の価値があります。
はい。ただし、その可能性は非常に低く、インデックスを使用するという決定に影響を与えるべきではありません。
場合によっては、SQL Server クエリ アナライザーが最適ではない実行プランを選択することがあります。考えられる実行プランの数は一見したよりもはるかに多いため (n
テーブルの単純な結合によってn!
実行プランが既に生成されているため)、SQL Serverは知識に基づいて推測する必要があります。それらが時々間違っているのは推測の性質です。
まれなケースですが、過去数年間に数回発生するのを見てきました。その場合 (およびその場合のみ)、インデックスが存在しなければ、より適切な計画が選択されていたでしょう。ただし、通常、インデックスは何らかの理由で存在するため、インデックスを削除することは、この問題を解決するための正しい方法ではありません。正しい方法は、オプティマイザーが適切なプランを選択できるように、このクエリ (およびこのクエリのみ) にヒントを追加することです。
はい、インデックスは SELECT のパフォーマンスを低下させる可能性があります。データベース エンジンがどのように動作するかを理解することが重要です。データはディスク上の「ページ」に保存されます。インデックスを使用すると、テーブル内の 1 つ以上の列に特定の値を持つ特定のページにアクセスできます。
これは、特定の値を探している場合に最適です。
ただし、テーブル内のすべての行を調べる必要があるクエリを考えてみましょう。表を調べると、ページを順番に読み、重要なことに、ページのすべての行を 1 回の読み取りで取得します。読み取り回数は、テーブル内のページ数です。さらに、ページキャッシュは先読み読み取りで読み取りを最適化でき、使用されなくなったページは単純に上書きされます。
同じ読み取りにインデックスを使用すると、一度に 1 ページではなく、一度に 1 つのレコードがテーブルを通過します。これにより、ページ全体がランダムに読み取られます。最悪の場合、テーブル内のレコードごとに 1 回の読み取りが発生し、パフォーマンスが大幅に低下する可能性があります。さらに、インデックス自体がページ キャッシュの一部を占有するため、他の操作のためのメモリが減少します。
一般に、SQL エンジンのオプティマイザ コンポーネントは、これら 2 つの状況を適切に区別します。重要な指標の 1 つは、クエリの選択性です。クエリが返す行数 (ページ数に関してオプティマイザが確認する行数) は? 行数がページ数とほぼ同じである場合、オプティマイザはインデックス スキャンではなくフル テーブル スキャンを検討します。
確かに他にも考慮事項がありますが、一般的に、インデックスは単純な選択クエリのパフォーマンスを損なう可能性があります。一般に、オプティマイザは適切に機能しますが、最高のオプティマイザでさえだまされる異常なケースが時々あります。
私の推測では、クエリ プラン オプティマイザを混乱させるようなインデックスを作成し、それが手元のクエリに対して非効率的なインデックスを選択することになると思います。
これは実装に依存する可能性がありますが、原則としてインデックスの速度が低下することはありませんSELECT
。
INSERT
明らかに、彼らは減速することができますUPDATE
.