1

キャラクター:

  • idBIGINT _
  • geo_point POINT(PostGIS)
  • stroke_when TIMESTAMPTZ(インデックス付き!)
  • stroke_when_second倍精度

PostgeSQL 9.1、PostGIS2.0。

1.クエリ:

SELECT ST_AsText(geo_point) 
FROM lightnings 
ORDER BY stroke_when DESC, stroke_when_second DESC 
LIMIT 1

合計実行時間:31100.911ミリ秒

EXPLAIN(ANALYZEオン、VERBOSEオフ、COSTSオン、BUFFERSオン):

Limit  (cost=169529.67..169529.67 rows=1 width=144) (actual time=31100.869..31100.869 rows=1 loops=1)
  Buffers: shared hit=3343 read=120342
  ->  Sort  (cost=169529.67..176079.48 rows=2619924 width=144) (actual time=31100.865..31100.865 rows=1 loops=1)
        Sort Key: stroke_when, stroke_when_second
        Sort Method: top-N heapsort  Memory: 17kB
        Buffers: shared hit=3343 read=120342
        ->  Seq Scan on lightnings  (cost=0.00..156430.05 rows=2619924 width=144) (actual time=1.589..29983.410 rows=2619924 loops=1)
              Buffers: shared hit=3339 read=120342

2.別のフィールドを選択します。

SELECT id 
FROM lightnings 
ORDER BY stroke_when DESC, stroke_when_second DESC 
LIMIT 1

合計実行時間:2144.057ミリ秒

EXPLAIN(ANALYZEオン、VERBOSEオフ、COSTSオン、BUFFERSオン):

Limit  (cost=162979.86..162979.86 rows=1 width=24) (actual time=2144.013..2144.014 rows=1 loops=1)
  Buffers: shared hit=3513 read=120172
  ->  Sort  (cost=162979.86..169529.67 rows=2619924 width=24) (actual time=2144.011..2144.011 rows=1 loops=1)
        Sort Key: stroke_when, stroke_when_second
        Sort Method: top-N heapsort  Memory: 17kB
        Buffers: shared hit=3513 read=120172
        ->  Seq Scan on lightnings  (cost=0.00..149880.24 rows=2619924 width=24) (actual time=0.056..1464.904 rows=2619924 loops=1)
              Buffers: shared hit=3509 read=120172

3.正しい最適化:

SELECT id 
FROM lightnings 
ORDER BY stroke_when DESC 
LIMIT 1

合計実行時間:0.044ミリ秒

EXPLAIN(ANALYZEオン、VERBOSEオフ、COSTSオン、BUFFERSオン):

Limit  (cost=0.00..3.52 rows=1 width=16) (actual time=0.020..0.020 rows=1 loops=1)
  Buffers: shared hit=5
  ->  Index Scan Backward using lightnings_idx on lightnings  (cost=0.00..9233232.80 rows=2619924 width=16) (actual time=0.018..0.018 rows=1 loops=1)
        Buffers: shared hit=5

ご覧のとおり、SQLオプティマイザーがインデックスを使用する場合、クエリは非常に原始的ですが、2つの悪い衝突と非常に異なる衝突があります。

  1. オプティマイザーがインデックスを使用しない場合でも、idの代わりにAs_Text(geo_point)を使用すると、非常に時間がかかるのはなぜですか?結果は1行だけです!
  2. インデックス付けされていないフィールドがORDERBYに表示されている場合、1次インデックスを使用することはできません。実際には、DBには毎秒数行しか表示されないことに注意してください。

もちろん、上記は、より複雑な構造から抽出された単純化されたクエリです。通常、複雑なフィルターを適用して、日付範囲で行を選択します。

4

2 に答える 2

2

PostgreSQLは、インデックスを使用して、最初の2つのクエリに必要な順序で値を生成することはできません。2つ以上の行が同一store_whenである場合、それらは任意の順序でインデックススキャンから返されます。行の正しい順序を決定するには、2次ソートパスが必要になります。PostgreSQLエグゼキュータにはそのセカンダリソートを実行する機能がないため、フルソートアプローチにフォールバックします。

その順序でテーブルを定期的にクエリする必要がある場合は、現在のインデックスを両方の列を含む複合インデックスに置き換えます。

現在のクエリを、次の最大値のみで2次ソートを明示的に指定する形式に変換できますstore_when

 SELECT ST_AsText(geo_point) FROM lightnings
 WHERE store_when = (SELECT max(store_when) FROM lightnings)
 ORDER BY stroke_when_second DESC LIMIT 1
于 2012-09-17T13:30:25.137 に答える
1

最初のステップは次のとおりです。{stroke_when、stroke_when_second}に複合インデックスを作成します

于 2012-09-17T13:27:43.257 に答える