2012-03-15 39 views
1

私はStackOverflowの上で同様の質問がある知っているが、私のテーブルの上に別のインデックスをテストした後、私はかなりのインデックスがどのように動作するかを理解していないと思うし、誰かができれば、私はそれが欲しいですクエリのパフォーマンスについて、私が経験している動作を説明してください。私は例として、このクエリを使用してい複数の単一フィールドインデックス対複数フィールドインデックス

は、私は詳細にそれを説明しようとするつもりです:

SELECT ss1.PlayerID, ss1.Name, ss1.Series, ss1.LanesNum, ss1.Date, ss1.LeagueName, ss1.Season FROM SeriesScores ss1 
      JOIN (SELECT Series, Gender, LanesNum, Bowlout, Season FROM SeriesScores 
      WHERE Gender = ? AND LanesNum = ? AND Series > -1 AND Bowlout = 'No' AND Season = '2011-2012' 
      ORDER BY Series DESC LIMIT 0,?) as ss2 
      USING(series, gender, lanesNum, bowlout, season) 
      ORDER BY ss1.Series DESC 

この問合せは、各ペアのために与えられたシーズンでボーリング最高のシリーズを取得するために使用されますボウリング場の男性と女性の両方のための車線の。

車線の所定の対のネクタイがあります場合、私はすべての名前が出てくるしたいので、私は自分自身に、テーブルに参加する代わりに、MAX集計関数を使用しています。

基本的に、私は内部SELECTが返すものと一致するすべてのフィールドを結合します。その内側のSELECTは、特定の性別と与えられた1組のレーンのトップXプレーヤーを返します。

使用した部分は、私が選択します探していますと同じ性別、シリーズ、lanesNumや季節で、出て圧倒されていないことを確認選手だけになります。私は最高のシリーズから最も低いシリーズまで注文します。

このクエリはforループにあり、男性の場合は12回、女性の場合は12回(ボーリングセンターの12ペアのレーン)、レーン番号と性別パラメータのみが変更されます。

私は、アプリケーション(男性用1つのベクトル、女性のための1)で結果を表示するには、Javaで二つの異なるベクトルですべての結果を置きます。

インデックスがまったくなくても、結果をベクトルとそのすべてに入れることを含むすべてを実行するには約11秒かかります。 (男性12問で5.5秒、女性で12秒)。 (性別、lanesNum、シリーズ)上のインデックスを持つ

それは私のニーズのために許容可能な速度よりもより多くのだから、それは、驚くべきである、全体のことのために0.04秒かかります。

私はWHERE句で使用している最も重要なフィールドなのでインデックスを使用しましたが、他のものを試して実際に他のインデックスを使用していたため、私の質問は100%以上低かった。また、もし私が "ボウルアウト"と "シーズン"をそのインデックスに追加すれば、より高速なクエリを得ることができるのだろうかと思っています。

最初に列のインデックスを1つ試し、パフォーマンスをテストしたかったのです。それはそれらのクエリのすべてを合計22秒にするインデックスです。

私は索引をどこで使うべきか、複数のフィールドで使うべきか、単一のフィールドで複数の索引を使うべきなのか分かりませんでした。また、私は理解しませんどのように(間違った)インデックスを使用すると実際にパフォーマンスが悪化する可能性があります。ただ一つのクエリのためにあまりにもaggresivelyインデックスを最適化

答えて

1

は、他のクエリ(したがって、実際のアプリケーション、またはそれの次のバージョンを)減速のリスクを実行します。ただし、インデックスのパフォーマンスを分析するための練習として、それを正確に実行しましょう。

インデックスは、複数の方法でクエリのパフォーマンスに影響します。それらの存在は、データベースサーバがデータに到達するために使用するアルゴリズムを実際に完全に変更することができます。素敵な概要はhereですが、クエリがシンプルで、実際にデータベースに関連するインデックス(テーブルの主キーをサポートするために自動的に作成されたインデックス)がほとんどありませんので、ストーリーを大幅に簡略化できます。

インデックスが良好な場合は、テーブル間のデータの相互参照が高速になります。理想的には、USING句とWHERE句に列が含まれており、ほとんどの場合、テーブルの一意の行を参照するのに十分な数の列が含まれています。それより少ないものが含まれていれば、それはデータベースサーバによってまだ使用されるかもしれませんが、残りの行は1つずつ訪問されなければなりません。

インデックスだけでなく、テーブルから選択するすべてのデータも含まれています(はい、2つのテーブルが実際には自己結合のために同じ物理テーブルである場合は意味があります。同じデータを使用して2つの異なるテーブルであるかのように処理します)。このような「完全カバー索引」の利点は、データベースサーバーがテーブルをまったく訪問する必要がないことです。すべての列が索引で使用可能です。

索引に関する項目の順序。索引の一番左の列がUSING句またはWHERE句に表示されることが特に重要です。そうでなければ、単一の参照のマッチングデータがそのインデックスの多くの場所に現れる可能性があるため、インデックスはほとんど使用できなくなります。それはまた、非常に選択的でなければなりません(テーブルには多くの異なる値があります)。この最初の手を見るためにいくつかの実験をしましょう。

このため、私があなたにお勧めする最初の選択肢のインデックスはseries, gender, lanesNum, bowloutです。あなたもこのクエリのために非常に良いものです。

明示的に複数のインデックスを作成することはあまりありません。クエリーがとても簡単であるため、クエリーの実行中に複数のクエリーを使用することは基本的にありません。だから最も有用なものはおそらく勝利し、他のすべては無視されるでしょう。

あなたの最後の質問:余分なインデックスはUPDATE、INSERT、DELETE文の実行が遅くなると考えている人もいますが、これは索引を更新するオーバーヘッドがかかるためです。データベースサーバはクエリを計算する複数のアルゴリズムを考慮しているため(最初から2つの論理テーブルを使用し、使用する自動または明示的なインデックスは使用しない)、間違ったプランを選択する可能性があります。インデックスはデータを知らなくても魅惑的に見えるかもしれません分布を考えれば非常に非生産的である。

実際にデータベースサーバーにデータを分析させ、その後のクエリを合理的に最適化するのに役立ついくつかの統計情報を記録し、おそらくデータを22秒間実行しないようにする方法があります統計はもはや真実ではない)。これがANALYZEコマンドです。それ以降のsqliteのパフォーマンスを最大限に引き出すために、インデックスを変更した後に毎回発行してください。本番データベースでは、毎晩夜間にANALYZEを実行するようにスケジュールを設定することで、データベースが時間の経過とともに徐々に減速することもなく、無害で無駄なインデックスを追加した後に突然実行することもできます。

+0

非常に明確で詳細な回答、ありがとう!このクエリは単純なので、他のインデックスを作成するのにあまり役に立たないと言ったときの簡単な質問です...私は他の(時にはもっと複雑な)クエリを持っているので、同じテーブルを使用する他のクエリのインデックスを追加するほうが有益ですデータベースが代わりに他のインデックスを使用する必要があると考える場合、このクエリを遅くすることができますか?それ以外は、私はすべてを得ると思う、おかげで! –

+0

私が最初に言ったように、これは単一の質問精神運動のみでした。一度あなたは複数のクエリを持っている、あなたはそれらのすべてのまともなパフォーマンスが欲しいでしょう。テーブルごとに1つのインデックスを用意して、すべてのテーブルに対応できるようにしたい場合がありますが、必ずしもそうである必要はありません。統計が更新されると、追加のインデックスは、クエリの最初の実行中またはクエリオプティマイザ自体がすばらしい仕事を実行できない場合を除いて、減速を引き起こしてはいけません。 –

+0

@Adam - 前回のコメントで最初に実行したときの非常に小さな減速は、クエリを評価するために使用できるさまざまなアルゴリズムを評価するクエリオプティマイザです。その後、同じクエリに対して勝利アルゴリズム(いわゆるクエリプラン)が再利用されます。 –

関連する問題