5

の最小値が必要ですrunnerId

このクエリ:

SELECT "runnerId" FROM betlog WHERE "marketId" = '107416794' ;

80ミリ秒かかります(1968年の結果行)。

これ:

SELECT min("runnerId") FROM betlog WHERE "marketId" = '107416794' ;

1600ミリ秒かかります。

最小値を見つけるためのより速い方法はありますか、それともJavaプログラムで最小値を計算する必要がありますか?

"Result  (cost=100.88..100.89 rows=1 width=0)"
"  InitPlan 1 (returns $0)"
"    ->  Limit  (cost=0.00..100.88 rows=1 width=9)"
"          ->  Index Scan using runneridindex on betlog  (cost=0.00..410066.33 rows=4065 width=9)"
"                Index Cond: ("runnerId" IS NOT NULL)"
"                Filter: ("marketId" = 107416794::bigint)"

CREATE INDEX marketidindex
  ON betlog
  USING btree
  ("marketId" COLLATE pg_catalog."default");

別のアイデア:

SELECT "runnerId" FROM betlog WHERE "marketId" = '107416794' ORDER BY "runnerId" LIMIT 1 >1600ms
SELECT "runnerId" FROM betlog WHERE "marketId" = '107416794' ORDER BY "runnerId" >>100ms

LIMITクエリを遅くするにはどうすればよいですか?

4

3 に答える 3

8

必要なのは複数列のインデックスです:

CREATE INDEX betlog_mult_idx ON betlog ("marketId", "runnerId");

興味がある場合は、PostgreSQLの複数列インデックス、リンク、およびベンチマークに関する詳細情報が、dba.SEのこの関連する質問にあります。

どのように私は理解しましたか?
複数列のインデックスでは、行はインデックスの最初の列( "marketId")によって順序付けられ(したがってクラスター化され)、各クラスターはインデックスの2番目の列によって順番に並べられます。したがって、最初の行は条件に一致します。min("runnerId")。これにより、インデックススキャンが非常に高速になります。

LIMITクエリを遅くするという逆説的な影響に関しては、Postgresクエリプランナーには弱点があります。一般的な回避策は、CTEを使用することです(この場合は必要ありません)。この最近の密接に関連する質問の下で詳細情報を見つけてください:
PostgreSQLクエリに時間がかかりすぎる

于 2012-11-24T22:47:25.807 に答える
1

minステートメントは、テーブル全体の順次スキャンを使用してPostgreSQLによって実行されます。次のアプローチを使用してクエリを最適化できます。SELECTcolFROMsometable ORDER BY col ASC LIMIT 1;

于 2012-11-24T22:41:02.657 に答える
1

インデックスがオンになっている("runnerId")(または少なくとも"runnerId"上位列として)が、インデックスがない場合は、その列のインデックスを使用し("marketId", "runnerId")て一致するすべての行を渡し、そのセットから最小値を選択するコストを比較しました。インデックスを使用してスキャンし、一致する最初の行が見つかったときに停止するコスト。利用可能な統計と、そのインデックスのインデックスエントリ内に値がランダムに分散されるという仮定に基づいて、後者のアプローチの方がコストが低いと推定されました。"marketId""runnerId""runnerId""marketId""marketId""runnerId"

また、テーブル全体をスキャンし、一致する行から最小値を選択するコストや、おそらく他の多くの選択肢も見積もりました。常に特定のタイプのプランを使用するわけではありませんが、すべての選択肢のコストを比較します。

問題は、値が範囲内でランダムに分散されるという仮定が(この例のように)必ずしも正しいとは限らず、範囲の高い割合をスキャンして、最後に潜んでいる行を見つけることです。"marketId"選択した値がインデックスの先頭近くで利用できる、の一部の値の場合"runnerId"、この計画は非常に高速である必要があります。

PostgreSQL開発者コミュニティでは、データの分散が想定されていなかった場合に、実行時間が長くなるという点で「危険」な計画にバイアスをかける方法について議論されており、相関するように複数列の統計を追跡する作業が行われています。値はそのような問題に遭遇しません。今後数回のリリースで、この分野の改善が見込まれます。それまでは、Erwinの提案は、この問題を回避する方法の目標に向かっています。

基本的には、より魅力的な計画を利用できるようにするか、最適化の障壁を導入することになります。この場合、("marketId", "runnerId")-にインデックスを追加することで、より魅力的なオプションを提供できます。これにより、答えに直接到達するための非常に直接的な方法が可能になります。プランナーはその代替案に非常に低いコストを割り当て、それを選択させます。インデックスを追加したくない場合は、次のようにして最適化バリアを強制できます。

SELECT min("runnerId")
  FROM (SELECT "runnerId" FROM betlog
          WHERE "marketId" = '107416794'
          OFFSET 0) x;

句があるOFFSET場合(オフセットがゼロの場合でも)、サブクエリが個別に計画され、その結果が外部クエリに送られます。これは、最適化の障壁がない場合の1600ミリ秒ではなく、80ミリ秒で実行されると思います。もちろん、インデックスを追加できる場合は、データがキャッシュされるときのクエリの速度は1ミリ秒未満である必要があります。

于 2012-11-25T18:32:40.290 に答える