Postgres 不够聪明,无法结合 WHERE 和 ORDER BY 中的字段进行索引扫描?

And*_*ndy 4 postgresql performance optimization order-by query-performance

我在 Postgres 9.6 中有下表:

                                       Table "public.TagNotifications"
    Column    |            Type             |                            Modifiers                            
--------------+-----------------------------+-----------------------------------------------------------------
 createdAt    | timestamp with time zone    | not null default now()
 updatedAt    | timestamp with time zone    | not null default now()
 id           | integer                     | not null default nextval('"TagNotifications_id_seq"'::regclass)
 tag          | character varying(255)      | not null
 triggerId    | integer                     | 
 userId       | integer                     | not null
 comparison   | "TagNotificationComparison" | 
 setpoint     | double precision            | 
 severity     | "TagNotificationSeverity"   | 
 acknowledged | boolean                     | not null default false
 value        | double precision            | 
Indexes:
    "TagNotifications_pkey" PRIMARY KEY, btree (id)
    "TagNotificactions_userId_acknowledged_createdAt_tag_id" btree ("userId", acknowledged, "createdAt" DESC, tag, id)
    "TagNotificactions_userId_acknowledged_tag_createdAt_id" btree ("userId", acknowledged, tag, "createdAt" DESC, id)
Foreign-key constraints:
    "TagNotifications_tag_fkey" FOREIGN KEY (tag) REFERENCES "Metadata"(tag) ON UPDATE CASCADE ON DELETE CASCADE
    "TagNotifications_triggerId_fkey" FOREIGN KEY ("triggerId") REFERENCES "TagNotificationTriggers"(id) ON UPDATE CASCADE ON DELETE SET NULL
    "TagNotifications_userId_fkey" FOREIGN KEY ("userId") REFERENCES "Users"(id) ON UPDATE CASCADE ON DELETE CASCADE
Run Code Online (Sandbox Code Playgroud)

我正在尝试确保以下查询(以及基于游标分页的类似查询)的良好性能:

EXPLAIN
SELECT * FROM "TagNotifications"
WHERE ("userId" = 2 AND "acknowledged" = false)
ORDER BY "tag" ASC, "createdAt" DESC, "id" ASC
LIMIT 6;
                                     QUERY PLAN                                     
------------------------------------------------------------------------------------
 Limit  (cost=840.10..840.12 rows=6 width=75)
   ->  Sort  (cost=840.10..856.04 rows=6376 width=75)
         Sort Key: tag, "createdAt" DESC, id
         ->  Seq Scan on "TagNotifications"  (cost=0.00..725.81 rows=6376 width=75)
               Filter: ((NOT acknowledged) AND ("userId" = 2))
(5 rows)
Run Code Online (Sandbox Code Playgroud)

为什么 Postgres 不够聪明,无法在这种情况下使用索引?如果我包含"userId"acknowledgedin ORDER BY,它使用索引,但由于WHERE条件,这应该不是必需的:

EXPLAIN
SELECT * FROM "TagNotifications"
WHERE ("userId" = 2 AND "acknowledged" = false)
ORDER BY "userId" ASC, "acknowledged" ASC, "tag" ASC, "createdAt" DESC, "id" ASC
LIMIT 6;
                                                                   QUERY PLAN                                                                   
------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.41..2.27 rows=6 width=75)
   ->  Index Scan using "TagNotificactions_userId_acknowledged_tag_createdAt_id" on "TagNotifications"  (cost=0.41..1974.27 rows=6376 width=75)
         Index Cond: (("userId" = 2) AND (acknowledged = false))
         Filter: (NOT acknowledged)
(4 rows)
Run Code Online (Sandbox Code Playgroud)

jja*_*nes 5

它在 v10 中变得更加智能。

我认为它之前不够聪明的原因在这里描述:

https://www.postgresql.org/message-id/1788.1481605684@sss.pgh.pa.us

我不知道如何总结,所以我只会说“索引中的布尔值令人困惑”