3

ブール値フィールド (「テスト」) にインデックスを持つテーブルがあります。true の場合はインデックスを使用するため読み込みが高速ですが、false の場合は使用しません。何か間違えている?

私はここにそれの説明分析を持っています:

DB_development=# explain analyze SELECT COUNT(*) FROM "users" WHERE "users"."is_test" = 't';
                                                                      QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost=22890.67..22890.68 rows=1 width=0) (actual time=1848.655..1848.656 rows=1 loops=1)
   ->  Index Scan using index_users_on_is_test on users  (cost=0.00..22846.51 rows=17665 width=0) (actual time=34.727..1844.081 rows=21457 loops=1)
         Index Cond: (is_test = true)
         Filter: is_test
 Total runtime: 1848.882 ms
(5 rows)

DB_development=# explain analyze SELECT COUNT(*) FROM "users" WHERE "users"."is_test" = 'f';
                                                      QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost=84505.74..84505.75 rows=1 width=0) (actual time=9557.632..9557.632 rows=1 loops=1)
   ->  Seq Scan on users  (cost=0.00..84063.72 rows=176807 width=0) (actual time=71.653..9533.595 rows=219531 loops=1)
         Filter: (NOT is_test)
 Total runtime: 9557.655 ms
(4 rows)

アップデート

私はここを見ました インデックスを無視できるブールフィールドにインデックスを追加しています... 非テストユーザーはテストユーザーと比較して実際にはかなり多いのが正しい原因だと思います。

DB_development=# SELECT COUNT(*) FROM "users" WHERE "users"."is_test" = 't';
 count
-------
 21457
(1 row)

DB_development=# SELECT COUNT(*) FROM "users" WHERE "users"."is_test" = 'f';
 count
--------
 219531
(1 row)

その場合...どうすれば簡単にカウントできますか?

アップデート

テーブルとインデックスの作成は次のとおりです。

  create_table "users", :force => true do |t|
    t.integer  "genre_id"
    t.integer  "country_id"
    t.boolean  "is_test",                                          :default => false
    t.datetime "created_at"
    t.datetime "updated_at"

    ... + 90 more fields (it's my main table)
  end

  add_index "users", ["country_id"], :name => "index_users_on_country_id"
  add_index "users", ["genre_id"], :name => "index_users_on_genre_id"
  add_index "users", ["is_test"], :name => "index_users_on_is_test"

  ... + 17 more indexes
4

4 に答える 4

2

SET enable_seqscan = off(テスト目的でのみ、他のクエリを大幅に遅くするため、本番環境で設定したり使用したりしないでください)再テストすると、インデックスを強制的に使用するとケースが遅くなるpostgresql.confことがおそらくわかります.false

個人的には、インデックスを削除して、代わりに に部分インデックスを追加し(is_test) WHERE (NOT is_test)ます。

WHERE (NOT is_test)テスト以外のインデックスの使用が大幅に高速化されるため、それが一般的なパターンである場合は、他の頻繁に使用されるインデックスを部分的にすることも検討します。

いずれにせよ、SET enable_seqscan = offケースがより高速である場合(かなりありそうにありません)、あなたのケースはrandom_page_cost高すぎる可能性があります。

また、PostgreSQL 9.2 を使用していた場合は、実際のケースに対してより適切な計画が得られるでしょう。通常は、インデックスのみのスキャンを使用して、テーブルのスキャンをまったく回避できます。インデックスがテーブルに対して十分に小さく、バキュームが十分に積極的に実行されている場合は、false の場合にもインデックスのみのスキャンを使用する可能性があります。テーブルが非常に広い (90 フィールド) ため、これはかなりありそうです。そのため、アップグレードを検討してください。

于 2013-06-20T12:21:10.033 に答える
1

これは完全に正常なようです... 行数ごとに、真の値は行の約 10% になります。false は残りの 90% を返します。後者の場合、インデックスに従って前後に移動するよりも、テーブル全体を読み取る方が高速です。(有用なほど選択的ではありません。)

于 2013-06-20T12:08:13.107 に答える