gpt4 book ai didi

PostgreSQL daterange 没有正确使用索引

转载 作者:行者123 更新时间:2023-11-29 11:48:02 27 4
gpt4 key购买 nike

我有一个简单的表,它有一个带有日期类型的 user_birthday 字段(可以是空值)

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)
)

在该字段上定义了一个索引(btree),规则为 NOTuser_birthday 为空。

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

重要的是要注意这个规则的实际用例是在一个更复杂的查询中,这不会导致重新检查 Cond 和位图堆扫描。在应用程序复杂查询中,这两种方法(有 120 万条记录)之间的差异是巨大的:查询 #1 在 415ms查询 #2 在 84 毫秒。

这是日期范围的错误吗?难道我做错了什么?或 datarange <@是否按设计执行?

pgsql-bugs mailing list 中也有讨论

最佳答案

BETWEEN includes上下边界。你的情况

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

匹配

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

我看到你提到了 btree 索引。为此,请使用简单的比较运算符。

详细manual page on which index is good for which operators .

范围类型运算符 <@ or @> would work with GiST indexes .
示例:
Perform this hours of operation query in PostgreSQL

关于PostgreSQL daterange 没有正确使用索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22824314/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com