44

私は EXPLAIN ANALYZE の結果を見ることにあまり慣れていません。クエリが遅すぎるという大きな問題があります。説明クエリの結果を解釈する方法を調べてみましたが、何を探すべきか、何が間違っているのかまだわかりません。どこかで大きな赤い光が点滅しているように感じますが、見えません。

したがって、クエリは非常に単純で、次のようになります。

EXPLAIN ANALYZE SELECT "cars".* FROM "cars" WHERE "cars"."sales_state" = 'onsale' AND "cars"."brand" = 'BMW' AND "cars"."model_name" = '318i' AND "cars"."has_auto_gear" = TRUE  LIMIT 25 OFFSET 0

そして、このような結果:

Limit  (cost=0.00..161.07 rows=25 width=1245) (actual time=35.232..38.694 rows=25 loops=1)
  ->  Index Scan using index_cars_onsale_on_brand_and_model_name on cars  (cost=0.00..1179.06 rows=183 width=1245) (actual time=35.228..38.652 rows=25 loops=1)
        Index Cond: (((brand)::text = 'BMW'::text) AND ((model_name)::text = '318i'::text))
        Filter: has_auto_gear"
Total runtime: 38.845 ms

ちょっとした背景: 私は Postgresql 9.1.6 を使用しており、Herokus 専用データベースで実行しています。私のデータベースには約7,5GbのRAMがあり、テーブルcarsには3,1Mの行が含まれ、約2,0Mの行にはsales_state = 'onsale'があります。テーブルには 170 列あります。使用するインデックスは次のようになります。

CREATE INDEX index_cars_onsale_on_brand_and_model_name
  ON cars
  USING btree
  (brand COLLATE pg_catalog."default" , model_name COLLATE pg_catalog."default" )
  WHERE sales_state::text = 'onsale'::text;

大きな明らかな問題を見ている人はいますか?

編集:

SELECT pg_relation_size('cars'), pg_total_relation_size('cars');

pg_relation_size: 2058444800 pg_total_relation_size: 4900126720

SELECT pg_relation_size('index_cars_onsale_on_brand_and_model_name');

pg_relation_size: 46301184

SELECT avg(pg_column_size(cars)) FROM cars limit 5000;

平均: 636.9732567210792995

制限なし:

EXPLAIN ANALYZE SELECT "cars".* FROM "cars" WHERE "cars"."sales_state" = 'onsale' AND "cars"."brand" = 'BMW' AND "cars"."model_name" = '318i' AND "cars"."has_auto_gear" = TRUE

Bitmap Heap Scan on cars  (cost=12.54..1156.95 rows=183 width=4) (actual time=17.067..55.198 rows=2096 loops=1)
  Recheck Cond: (((brand)::text = 'BMW'::text) AND ((model_name)::text = '318i'::text) AND ((sales_state)::text = 'onsale'::text))
  Filter: has_auto_gear
  ->  Bitmap Index Scan on index_cars_onsale_on_brand_and_model_name  (cost=0.00..12.54 rows=585 width=0) (actual time=15.211..15.211 rows=7411 loops=1)"
        Index Cond: (((brand)::text = 'BMW'::text) AND ((model_name)::text = '318i'::text))
Total runtime: 56.851 ms
4

2 に答える 2

33

このような単純な計画にはあまり役に立ちませんが、http://explain.depesz.comは非常に役に立ちます。http://explain.depesz.com/s/t4fiを参照してください。「統計」タブと「オプション」プルダウンに注意してください。

このプランの注意事項:

  • 推定行数 (183) は、実際の行数 (25) とほぼ同等です。行数の見積もり、または「1対1ではない」問題に関しては、桁違いに関心があります。(「政府の仕事に十分近い」正確さは必要ありません-「軍の契約会計に十分近い」で十分です)。選択性の推定と統計は妥当なようです。

  • 提供された 2 列の部分インデックス ( index scan using index_cars_onsale_on_brand_and_model_name) を使用しているため、部分インデックスの条件に一致します。で確認できますFilter: has_auto_gear。索引検索条件も表示されます。

  • 特に 2 列を超えているため、テーブルの行数がインデックスがかなり大きいことを意味することを考えると、クエリのパフォーマンスは妥当に見えます。一致する行は散在するため、各行でも個別のページの読み取りが必要になる可能性があります。

ここには何も問題はありません。ただし、このクエリは、PostgreSQL 9.2 のインデックス オンリー スキャンから大きな恩恵を受ける可能性があります。

ここにいくつかのテーブルが膨張している可能性がありますが、2 列のインデックスと膨大な数の行を考えると、応答時間は完全に不合理ではありません。ページ。ダウンタイムに余裕がある場合はVACUUM FULL、テーブルを再編成してインデックスを再構築してみてください。これにより、再構築中のしばらくの間、テーブルが排他的にロックされます。ダウンタイムを許容できない場合は、pg_reorgおよび/またはCREATE INDEX CONCURRENTLYおよびを参照してくださいALTER INDEX ... RENAME TO

EXPLAIN (ANALYZE, BUFFERS, VERBOSE)バッファアクセスなどを表示できるため、より有益な場合があります。

このクエリを高速化する可能性のあるオプションの 1 つは (ただし、他のクエリが多少遅くなるリスクがあります)、テーブルをパーティション分割しbrandて有効にすることconstraint_exclusionです。パーティショニングを参照してください。

于 2012-10-16T13:06:47.253 に答える
0

さて...私が最初に言えることは、データベースが(統計から)183行を取得することを期待しているということです。実際には、25行を取得しています。この場合、それはおそらくあまり関連性がありませんが(つまり、これらの少量で重い操作がない場合は、誤って見積もることを心配する必要はありません)。

より大きな問題(imho)は、25行の単純なインデックスルックアップに35ミリ秒かかることです。それは少し多いようです。データベースは、少なくともすべてのインデックスをメモリに保持するのに十分な重さですか?それは過度ではありませんが、私には少し遅いようです。

説明を見るには、explain.depesz.comを使用することをお勧めします:http://explain.depesz.com/s/sA6

于 2012-10-16T13:10:43.510 に答える