对于PostgreSQL v15.2,我使用以下表定义:

   CREATE TABLE IF NOT EXISTS postgres_air_bitemp.frequent_flyer_transaction(
    frequent_flyer_transaction_key integer NOT NULL DEFAULT
    nextval('postgres_air_bitemp.frequent_flyer_transaction_frequent_flyer_transaction_key_seq'
      ::regclass),
    frequent_flyer_id integer NOT NULL,
    level text ,
    booking_leg_id integer,
    award_points integer,
    status_points integer,
    effective temporal_relationships.timeperiod NOT NULL,
    asserted temporal_relationships.timeperiod NOT NULL,
    row_created_at timestamp with time zone NOT NULL DEFAULT now(),
    CONSTRAINT frequent_flyer_transaction_pk PRIMARY KEY (frequent_flyer_transaction_key),
    CONSTRAINT frequent_flyer_transaction_frequent_flyer_id_assert_eff_excl EXCLUDE USING gist (
        effective WITH &&,
        asserted WITH &&,
        frequent_flyer_id WITH =)
    )

我看到这个查询的查询计划:

    airlines=# explain analyze select * from
    postgres_air_bitemp.frequent_flyer_transaction t 
    where frequent_flyer_id=39189 and now()<@asserted and now()<@effective;
                                           QUERY PLAN                                                                              
# ----------------------------------------------------------------------------------------------------------------------------------------------------------------------
    Bitmap Heap Scan on frequent_flyer_transaction t  (cost=4.69..87.91 rows=21 width=74) (actual time=0.097..0.099 rows=1 loops=1)
        Recheck Cond: (frequent_flyer_id = 39189)
        Filter: ((now() <@ (asserted)::tstzrange) AND (now() <@ (effective)::tstzrange))
        Heap Blocks: exact=1
        ->  Bitmap Index Scan on frequent_flyer_transaction_frequent_flyer_id_assert_eff_excl (cost=0.00..4.68 rows=21 width=0) (actual time=0.077..0.077 rows=1 loops=1)
            Index Cond: ((frequent_flyer_id = 39189) AND ((asserted)::tstzrange @> now()) AND ((effective)::tstzrange @> now()))
    Planning Time: 0.333 ms
    Execution Time: 0.172 ms
    (8 rows)

查询计划正确地使用了btree_gist索引,但随后它对由双时态时间范围过滤的frequent_flyer_id进行位图索引扫描,最后对frequent_flyer_id条件进行重新判断.为什么在初始btree_gist索引扫描之后需要执行后续步骤?

我希望看到一个查询计划,它只包含使用btree_gist索引的索引扫描.额外的步骤是必要的,因为gist索引是有损的,因此后续步骤是判断假阳性?

推荐答案

由于它期望找到12行,它可能认为位图扫描将导致比常规索引扫描更有效的IO.您可以设置enable_bitmapscan = off,看看它切换到了什么. 位图将始终按照物理顺序读取表,而索引扫描将按照由索引中条目的顺序确定的随机顺序读取表.

所有位图都有潜在的有损性(如果超过work_currency). 由于没有办法在计划时间保证它不会go 损耗,所以总是设置重新判断的机制. 然后这条线就会出现在计划中,即使它完全没有使用.

我不知道为什么@ conditions被filter重新判断而不是标准的重新判断.< 我认为这与now()只是稳定而非不可变有关,就好像我用文字时间戳替换它,然后判断从过滤器移动到recheck.这对我来说没有意义,这似乎是一个错过的优化,但一个微不足道的优化. 只需删除btree_gist并在两个时间范围列上创建gist索引,并看到计划看起来相似,就可以很容易地验证这与btree_gist无关.

Postgresql相关问答推荐

Qt,PostgreSQL -从NUERIC列检索max int64_t/uint64_t值

Postgres SQL执行加入

计算两个子查询之间的差异

如何在plpgsql中找到一行中的最大值?

Postgres 转储按顺序插入

使用 Heroku CLI、Postgres 的 SQL 语法错误

在 PostgreSQL 中返回插入的行

如果 PostgreSQL 数据库中存在,则删除表

从局域网访问 PostgreSQL 服务器

SQLAlchemy 和多个进程的连接问题

PostgreSQL:使用 psql 命令行实用程序时 Windows 上的编码问题

与 Oracle 的 CONNECT BY ... START WITH 等效的 PostgreSQL 语法是什么?

如何在 postgres 中使用 json_populate_recordset 解析 json

如何在带有 PostgreSQL 数据库的 Web 应用程序中拥有完整的离线功能?

防止 CHARACTER VARYING 字段中出现空字符串

具有 DEFAULT NULL 的 MySQL 列 ?

FOR EACH STATEMENT 触发器示例

PostgreSQL 使用 UUID 与文本作为主键

PostgreSQL 中是否有类似 zip() 函数的东西,它结合了两个数组?

判断 Postgres 中是否存在序列(plpgsql)