web-dev-qa-db-ja.com

SQLクエリの複雑さとパフォーマンスに関する一般的なルールはありますか?

1)SQLクエリの実行時間O(n)は、インデックスが使用されていない場合、結合の数と比較されますか?使用されていない場合、どのような関係が予想されますか?インデックスを改善できますか?実際のbig-Oの時間計算量、またはクエリ時間全体を一定の係数だけ短縮するのでしょうか。

少し漠然とした質問ですが、かなり変化すると思いますが、ここでは一般的な意味で話しています。

2)次のようなクエリがある場合:

SELECT  T1.name, T2.date
FROM    T1, T2
WHERE   T1.id=T2.id
        AND T1.color='red'
        AND T2.type='CAR'

マルチテーブル条件を評価する前に、DBが最初にT1.colorとT2.typeでシングルテーブルフィルタリングを実行すると想定していますか?このような場合、クエリをより複雑にすると、結合レベルのテストの対象となる行が少なくなるため、クエリが高速化される可能性がありますか?

34
Mr. Boy

これは、使用するクエリプランによって異なります。

インデックスがなくても、最近のサーバーはO(N * M)よりも高速なHASH JOINMERGE JOINを使用できます。

より具体的には、HASH JOINの複雑さはO(N + M)です。ここで、Nはハッシュテーブルで、Mはルックアップテーブルです。ハッシュとハッシュルックアップは常に複雑です。

MERGE JOINの複雑さはO(N*Log(N) + M*Log(M))です。これは、両方のテーブルを並べ替える時間とそれらをスキャンする時間の合計です。

SELECT  T1.name, T2.date
FROM    T1, T2
WHERE   T1.id=T2.id
        AND T1.color='red'
        AND T2.type='CAR'

インデックスが定義されていない場合、エンジンはHASH JOINまたはMERGE JOINのいずれかを選択します。

HASH JOINは次のように機能します。

  1. ハッシュテーブルが選択されます(通常、レコード数が少ないテーブルです)。 t1だと言う

  2. t1からのすべてのレコードがスキャンされます。レコードがcolor='red'を保持している場合、このレコードはidをキーとして、nameを値としてハッシュテーブルに入ります。

  3. t2からのすべてのレコードがスキャンされます。レコードがtype='CAR'を保持している場合、そのidがハッシュテーブルで検索され、すべてのハッシュヒットからのnameの値が、現在のdataの値とともに返されます。

MERGE JOINは次のように機能します。

  1. t1 (id, name)のコピーが作成され、idで並べ替えられます

  2. t2 (id, data)のコピーが作成され、idで並べ替えられます

  3. ポインタは、両方のテーブルの最小値に設定されています。

    >1  2<
     2  3
     2  4
     3  5
    
  4. ポインタはループで比較され、一致する場合はレコードが返されます。それらが一致しない場合、最小値のポインターが進められます。

    >1  2<  - no match, left pointer is less. Advance left pointer
     2  3
     2  4
     3  5
    
     1  2<  - match, return records and advance both pointers
    >2  3
     2  4
     3  5
    
     1  2  - match, return records and advance both pointers
     2  3< 
     2  4
    >3  5
    
     1  2 - the left pointer is out of range, the query is over.
     2  3
     2  4<
     3  5
    >
    

このような場合、クエリをより複雑にすると、結合レベルのテストの対象となる行が少なくなるため、クエリが高速化される可能性がありますか?

承知しました。

WHERE句のないクエリ:

SELECT  T1.name, T2.date
FROM    T1, T2

より単純ですが、より多くの結果を返し、より長く実行されます。

45
Quassnoi

あまりにも多くの異なるものを混同することに注意してください。調査する行数に基づくクエリの論理コスト、実際に返された行数に基づく(おそらく)小さい論理コスト、および調査する必要のあるページ数に基づく無関係の物理コストがあります。

3つは関連していますが、強くはありません。

調査される行数は、これらのコストの中で最大であり、制御が最も簡単ではありません。行は、結合アルゴリズムを介して一致する必要があります。これも、最も関連性が低いです。

返される行数は、クライアントアプリケーションとデータベース間のI/O帯域幅であるため、よりコストがかかります。

読み取られるページ数は、物理I/Oの数がさらに多いため、最もコストがかかります。これはデータベース内の負荷であり、すべてのクライアントに影響を与えるため、最もコストがかかります。

1つのテーブルを持つSQLクエリは[〜#〜] o [〜#〜]n)です。それが行数です。また、ページ数に基づく[〜#〜] o [〜#〜]p)です。

複数のテーブルがある場合、調べられる行は[〜#〜] o [〜#〜](nmです。 ..)。これがネストされたループのアルゴリズムです。ただし、関係のカーディナリティによっては、結果セットが[〜#〜] o [〜#〜]n)関係はすべて1:1であるため。ただし、各テーブルで一致する行を調べる必要があります。

ハッシュ結合は[〜#〜] o [〜#〜](n * log(n))インデックス+テーブル読み取りを[〜#〜] o [〜#〜]に置き換えます(n)直接ハッシュルックアップ。それでも[〜#〜] o [〜#〜]n)行を処理する必要がありますが、一部をバイパスしますインデックス読み取り。

マージ結合は、[〜#〜] o [〜#〜](nm)ネストされたループを[〜#〜] o [〜 #〜](log(n + m)(n + m))ソート操作。

インデックスを使用すると、物理コストを[〜#〜] o [〜#〜](log(n )m)テーブルの存在をチェックするだけの場合。行が必要な場合、インデックスは行へのアクセスを高速化しますが、一致するすべての行を処理する必要があります。 [〜#〜] o [〜#〜](nm)これは、インデックスに関係なく、結果セットのサイズであるためです。

この作業で調べたページは、インデックスの選択性に応じて、小さくなる場合があります

インデックスのポイントは、検査される行の数をそれほど減らすことではありません。これは、行をフェッチするための物理I/Oコストを削減するためです。

15
S.Lott

インデックスが使用されていない場合、SQLクエリの実行時間は結合数と比較してO(n)ですか?

通常、これらはO(n ^ m)になります。ここで、nは関連するテーブルごとのレコード数、mは結合されるテーブルの数です。

また、インデックス作成によって実際のbig-Oの時間計算量を改善できますか、それともクエリ時間全体を一定の要因だけ削減できますか?

両方。インデックスを使用すると、結合が大幅にフィルタリングされている場合(つまり、適切なWHERE句を使用している場合)に直接検索でき、適切な列にある場合は結合を高速化できます。

インデックスは、結合またはフィルタリングされている列にない場合は役に立ちません。

1
Welbog

クラスター化非クラスター化インデックス のしくみを確認してください

それは純粋な技術的観点からです...簡単な説明のために、私の親友のmladenは簡単な 理解する記事 索引付けを書いています。

インデックスは間違いなく役立ちますが、長所と短所を理解するために読むことをお勧めします。

0
JonH