El rango de fechas de PostgreSQL no usa el índice correctamente

Tengo una tabla simple que tiene un campo user_birthday con un tipo de fecha (que puede ser un valor 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)
)

Hay un índice (btree) definido en ese campo, con la regla de NOT user_birthday IS NULL.

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

Intentando seguir otra idea, agregué la extensiónbtree_gist y creó el siguiente índice:

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

Pero tampoco tuvo ningún efecto, ya que, por lo que pude leer, no se usa para la verificación de rango.

La versión de PostgreSQL es 9.3.4.0 (22)Postgres.app y el problema también existe en 9.3.3.0 (21)Postgres.app

Me han intrigado las siguientes consultas:

Consulta # 1:

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

Consulta # 2:

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

que, a primera vista, ambos deberían tener el mismo plan de ejecución, pero por alguna razón, aquí están los resultados:

Consulta # 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"

Consulta # 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"

Como puede ver, el<@ daterange no está utilizando el índice existente, mientrasBETWEEN hace.

Es importante tener en cuenta que el caso de uso real de esta regla está en una consulta más compleja, que no da como resultado el análisis Recheck Cond y Bitmap Heap. En la consulta compleja de la aplicación, la diferencia entre los dos métodos (con 1.2 millones de registros) es enorme: Consulta # 1 a 415ms Consulta # 2 a 84ms.

¿Es esto un error con el rango de fechas? ¿Estoy haciendo algo mal? odatarange <@ está funcionando según lo diseñado?

También hay una discusión en ellista de correo pgsql-bugs

Respuestas a la pregunta(1)

Su respuesta a la pregunta