Database 为什么Postgres不为我的查询使用更好的索引?

Database 为什么Postgres不为我的查询使用更好的索引?,database,postgresql,indexing,sql-order-by,postgresql-performance,Database,Postgresql,Indexing,Sql Order By,Postgresql Performance,我有一个表格,记录在类似Twitter的应用程序中谁在跟踪谁: \d follow Table "public.follow" . Column | Type | Modifiers ---------+--------------------------+---------------------------------------------

我有一个表格,记录在类似Twitter的应用程序中谁在跟踪谁:

\d follow
                               Table "public.follow" .
 Column   |           Type           |                      Modifiers
 ---------+--------------------------+-----------------------------------------------------
xid       | text                     |
followee  | integer                  |
follower  | integer                  |
id        | integer                  | not null default nextval('follow_id_seq'::regclass)
createdAt | timestamp with time zone |
updatedAt | timestamp with time zone |
source    | text                     |
Indexes:
  "follow_pkey" PRIMARY KEY, btree (id)
  "follow_uniq_users" UNIQUE CONSTRAINT, btree (follower, followee)
  "follow_createdat_idx" btree ("createdAt")
  "follow_followee_idx" btree (followee)
  "follow_follower_idx" btree (follower)
表中的条目数超过一百万,当我对查询运行explain Analysis时,我得到以下结果:

explain analyze SELECT "follow"."follower"
FROM "public"."follow" AS "follow"
WHERE "follow"."followee" = 6
ORDER BY "follow"."createdAt" DESC
LIMIT 15 OFFSET 0;
                                                                  QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------
Limit  (cost=0.43..353.69 rows=15 width=12) (actual time=5.456..21.497 
rows=15 loops=1)
->  Index Scan Backward using follow_createdat_idx on follow  (cost=0.43..61585.45 rows=2615 width=12) (actual time=5.455..21.488 rows=15 loops=1)
     Filter: (followee = 6)
     Rows Removed by Filter: 62368
Planning time: 0.068 ms
Execution time: 21.516 ms
为什么它在
followe\u-createdat\u-idx
上执行反向索引扫描,如果它使用
followe\u-idx
,执行速度可能会更快

这个查询在第一次运行时大约需要33毫秒,随后的调用大约需要22毫秒,我觉得这是更高的一个方面


我使用的是亚马逊RDS提供的Postgres9.5。知道这里可能发生了什么错误吗?

(follower,“createdAt”)
上的多列索引非常适合查询,正如您在测试中已经发现的那样

由于
“createdAt”
可以为空(未定义
非空
),因此您可能需要添加
上次为空
以查询和索引:

以及:

更多:

轻微的其他绩效影响:


  • (follower,“createdAt”)
    上的多列索引每行比
    (follower)
    上的简单索引大8字节-44字节对36字节。更多(btree索引的页面布局与表大致相同):

  • 热更新不能以任何方式更改索引中涉及的列。向索引中添加更多的列可能会阻止此优化—考虑到列名,这似乎不太可能。既然你在
    (“createdAt”)
    上有另一个索引,那也不是问题。更多:

  • 仅在
    (“createdAt”)
    上有另一个索引没有坏处(除了每个索引的维护成本(用于写入性能,而不是读取性能)。这两个索引都支持不同的查询。另外,您可能需要也可能不需要在
    (“createdAt”)
    上有索引。详细说明:


(follower,“createdAt”)
上的多列索引非常适合查询-正如您在测试中已经发现的那样

由于
“createdAt”
可以为空(未定义
非空
),因此您可能需要添加
上次为空
以查询和索引:

以及:

更多:

轻微的其他绩效影响:


  • (follower,“createdAt”)
    上的多列索引每行比
    (follower)
    上的简单索引大8字节-44字节比36字节。更多(b树索引的页面布局与表基本相同):

  • 热更新无法以任何方式更改索引中涉及的列。向索引中添加更多列可能会阻止此优化-考虑到列名,这似乎不太可能。而且由于您只有
    (“createdAt”)
    上有另一个索引,因此这也不是问题。更多信息:

  • 仅在
    (“createdAt”)
    上有另一个索引没有坏处(除了每个索引的维护成本(用于写入性能,而不是读取性能)。这两个索引都支持不同的查询。另外,您可能需要也可能不需要在
    (“createdAt”)
    上有索引。详细说明:


因为如果它在followee索引上进行查找,那么它就必须进行排序。如果这是follow\u followee索引的主要用途,您可能需要尝试在该索引上添加createdAt作为第二个字段。@user1937198在我这样做之后,计算时间从20毫秒减少到2毫秒。因此它起作用了。如果我同时保留这两个字段,对性能有什么影响
“follow\u createdat\u idx”b树(“createdat”)
索引和新创建的
“follow\u follower\u createdat\u idx”b树(follower,“createdat”)
index。因为在某些用例中,我需要只获取一个人正在跟踪的所有用户,其中第一个索引可能更为优化。因为如果它在followee索引上进行查找,则必须进行排序。如果这是follow\u followee索引的主要用途,则可能需要尝试在该索引上添加createdAt作为第二个字段。@user1937198在我这样做之后,计算时间从20毫秒下降到了2毫秒。所以它起作用了。如果我同时保留
“follow\u createdat\u idx”b树(“createdat”)
索引和新创建的
“follow\u follower\u createdat\u idx”b树(follower,“createdat”),会对性能产生什么影响
index。因为在某些用例中,我需要获得一个人正在跟踪的所有用户,其中第一个索引可能更为优化。
...
ORDER BY "follow"."createdAt" DESC NULLS LAST
"follow_follower_createdat_idx" btree (follower, "createdAt" DESC NULLS LAST)