3

日付のタイプの user_birthday フィールドを持つ単純なテーブルがあります (NULL 値にすることができます)

CREATE TABLE users
(
  user_id bigserial NOT NULL,
  user_email text NOT NULL,
  user_password text,
  user_first_name text NOT NULL,
  user_middle_name text,
  user_last_name text NOT NULL,
  user_birthday date,
  CONSTRAINT pk_users PRIMARY KEY (user_id)
)

そのフィールドには、NOT user_birthday IS NULL のルールで定義されたインデックス (btree) があります。

CREATE INDEX ix_users_birthday
  ON users
  USING btree
  (user_birthday)
  WHERE NOT user_birthday IS NULL;

別のアイデアをフォローアップしようとして、拡張機能を追加しbtree_gist、次のインデックスを作成しました。

CREATE INDEX ix_users_birthday_gist
  ON glances.users
  USING gist
  (user_birthday)
  WHERE NOT user_birthday IS NULL;

しかし、範囲チェックには使用されていないため、影響はありませんでした。

PostgreSQL のバージョンは 9.3.4.0 (22) Postgres.appで、問題は 9.3.3.0 (21) Postgres.app にも存在します。

次のクエリに興味をそそられました。

クエリ #1:

EXPLAIN ANALYZE SELECT *
FROM users
WHERE user_birthday <@ daterange('[1978-07-15,1983-03-01)')

クエリ #2:

EXPLAIN ANALYZE SELECT *
FROM users
WHERE user_birthday BETWEEN '1978-07-15'::date AND '1983-03-01'::date

一見すると、どちらも同じ実行計画を持つはずですが、何らかの理由で結果は次のようになります。

クエリ #1:

"Seq Scan on users  (cost=0.00..52314.25 rows=11101 width=241) (actual
time=0.014..478.983 rows=208886 loops=1)"
"  Filter: (user_birthday <@ '[1978-07-15,1983-03-01)'::daterange)"
"  Rows Removed by Filter: 901214"
"Total runtime: 489.584 ms"

クエリ #2:

"Bitmap Heap Scan on users  (cost=4468.01..46060.53 rows=210301 width=241)
(actual time=57.104..489.785 rows=209019 loops=1)"
"  Recheck Cond: ((user_birthday >= '1978-07-15'::date) AND (user_birthday
<= '1983-03-01'::date))"
"  Rows Removed by Index Recheck: 611375"
"  ->  Bitmap Index Scan on ix_users_birthday  (cost=0.00..4415.44
rows=210301 width=0) (actual time=54.621..54.621 rows=209019 loops=1)"
"        Index Cond: ((user_birthday >= '1978-07-15'::date) AND
(user_birthday <= '1983-03-01'::date))"
"Total runtime: 500.983 ms"

ご覧のとおり、<@ daterangeは既存のインデックスを利用していませんが、利用して BETWEENいます。

このルールの実際の使用例は、より複雑なクエリであり、Recheck Cond および Bitmap Heap スキャンにはならないことに注意してください。アプリケーションの複雑なクエリでは、2 つの方法 (120 万レコード) の違いは非常に大きく、クエリ #1 は 415 ミリ秒、クエリ #2 は 84 ミリ秒です。

これは日付範囲のバグですか? 私は何か間違ったことをしていますか?またはdatarange <@設計どおりに実行されていますか?

pgsql-bugs メーリング リストにも議論があります。

4

1 に答える 1

2

BETWEEN 上下の境界線を含みます。あなたの状態

WHERE user_birthday BETWEEN '1978-07-15'::date AND '1983-03-01'::date

マッチ

WHERE user_birthday <@ daterange('[1978-07-15,1983-03-01]')

あなたがbtreeインデックスについて言及しているのを見ました。そのためには、単純な比較演算子を使用します。

どのインデックスがどの演算子に適しているかについての詳細なマニュアル ページ。

範囲型演算子<@or@>は、GiSTインデックスで機能します。
例:
PostgreSQL でこの稼働時間のクエリを実行する

于 2014-04-02T23:03:08.843 に答える