3

最近のインタビューSELECTで、MySQL データベースのクエリが非常に遅い理由を尋ねられ、次のように思いつきました。

  1. 選択で複数JOINの が実行されている
  2. キー フィルター フィールドにインデックスがない (インデックス?)

問題の解決策についても尋ねられ、私は次のように言いました。

  1. クエリの重要性が高い場合は、データを非正規化します (これがデータの重複につながることはわかっていますが、 JOINs を回避する別の方法はありますか?)
  2. フィルター列にインデックスを追加します。

SQL クエリが非効率になる理由について、他に特徴はありますか? クエリを高速化する方法に関するヒントを純粋に探していることに注意してください。DBサーバーは完璧であると仮定してください:-)

4

3 に答える 3

8

クエリが遅くなる理由はいくつかあります。いずれにせよ、クエリ プランナーが何をしているかを実際に確認するには、クエリ プランナーを実行する必要がありますexplain。ほとんどの DBMSのexplainコマンドは、クエリ プランナーが使用するインデックスがある場合は、取得できると予想されるデータの行数、および結果を取得する前に処理する必要があるデータの行数を示します。

ここで、クエリの実行が遅くなる具体的な理由をいくつか挙げると、インデックスについては正しいです。インデックスがないと、クエリに含まれるテーブルが順次スキャンされ、それらのテーブルが大きい場合は処理が遅くなる可能性があります。結合する列または where 句で使用する列にインデックスを作成すると、間違いなく役立ちます。ただし、場合によっては、クエリ プランナーの機能が不十分なため、「force」コマンドを使用して使用するインデックスを指定する必要があります。

参加すると速度が遅くなるというのは誤解です。通常、単一レベルの結合は問題ありません。たとえば、テーブル A からデータを選択し、B を A に、C を A に結合するとします。テーブル B および C への結合は 1 レベルの結合です。複数レベルの結合は、処理に時間がかかります。そのため、データ ウェアハウスやデータ マートではスター スキームが好まれます。これは、メトリックを含む単一の大きなテーブルであり、クエリが実行されるファクト テーブルであり、それに結合される記述データを含む他のテーブル、ディメンション テーブルがあります。スター スキーマは、複数レベルの結合を回避するため、レポート クエリをすばやく実行できます。

テーブルを非正規化するのは魅力的ですが、それをしないことを強くお勧めします。データベースの非正規化を開始すると、格納するデータの量がこれまで以上に大きくなり、スケーリングの問題が発生した場合に、深刻な問題に直面することになります。同様に、非正規化されたテーブルを維持するには、エンジニアがスキーマについて実際に十分な知識を持っている必要があり、それがより困難になり、技術的負債になります。確かにそれは短期的な利益ですが、長期的な苦痛は、あなたがそれをしたいと思う本当に正当な理由がなければならないことを意味します. スケーリングが必要な数年にわたるプロジェクトをいくつか実行すると、非正規化の痛みが実際にわかります。

必要に応じて、本番データベースのデータを使用して構築および更新されるレポート データベース、データ マート、またはデータ ウェアハウスを分離することが望ましい場合がよくあります。これにより、実行したいレポート クエリを実際にサポートするスキーマを自由に設計できるようになり、運用データベースのハッキングを防ぐことができます。

リソースが不足している場合、別のデータベースに代わる優れた方法は一時テーブルです。一時テーブルは、データベース接続/セッションの存続期間中存在するテーブルです。他の接続/セッションはそれを表示またはアクセスできず、分離品質であり、それらを使用して、より大規模でより複雑なクエリで使用するデータを保存およびインデックス化できます。コンソールを介してデータベースとやり取りしている場合は、非常に簡単に使用できます。プログラムで作業していて接続プールがある場合は、完了したらテーブルを削除する必要があるかもしれません。よく思い出せませんが、片付けは決して悪いことではありません。

クエリが遅くなる明らかな理由の 1 つは、大量のデータを選択していることです。それぞれが数億行の chars(1000) フィールドを持つ複数のテーブルをクロス結合しようとすると、結合を実行するために DBMS が仮想メモリを掘り始める可能性があります。インデックスがある場合でも、ディスクのスワッピングにつながる可能性があります。スワッピングが発生し始めたら、slowville へようこそ。

サブセレクト ( select a, b, (select c, d from e where e.id = a) from f) を選択するか、where 句でサブセレクトを使用すると、実際にはデータの各行に対して実行されるクエリであるため、非常に遅くなる可能性があります。結合で副選択を使用してもその問題は発生しませんが、基本的にインデックスなしで一時テーブルに結合しているため、その副選択で取得するデータの量によっては、速度が低下する可能性もあります。

セットが非常に大きい場合、inコマンドも問題になる可能性があります。繰り返しますが、大きなセットは基本的にインデックスのない大きな一時テーブルであるため、特定の値がセットに含まれているかどうかを確認するたびに、順次スキャンを実行しています。

これらは、私が今考えることができる最も顕著な理由です。他にもありますが、スタックオーバーフロー応答の範囲を超えていると思います;-)

于 2011-11-29T11:59:04.177 に答える
2

sargableでないクエリ - すなわち。DBMS は、適切なインデックスが存在する場合でも、それを利用することはできません。解決策 - クエリをリファクタリングしてサーガブルにします。

ディスク キャッシュを必要とするメモリ集約型のクエリ。解決策 - 追加の RAM とより高速なディスク アクセス (より高速なディスク、RAID ストライピングなど) でサーバーをアップグレードします。

于 2011-11-29T11:53:05.137 に答える