PostgreSQL多列索引与比较("<"和">")运算符连接

hal*_*fak 4 sql postgresql indexing optimization

我正试图利用PostgreSQL中的多列btree索引在两个表之间执行恼人的连接.

               Table "revision_main"
     Column     |          Type          | Modifiers 
----------------+------------------------+-----------
 revision_id    | integer                | 
 page_id        | integer                | 

Indexes:
    "revision_main_pkey" UNIQUE, btree (revision_id)
    "revision_main_cluster_idx" btree (page_id, "timestamp") CLUSTER
Run Code Online (Sandbox Code Playgroud)

此表包含Wiki中页面的修订版(约3亿行).我的表中有更多的列,但是我已经放弃了这个例子,因为它们无关紧要.

               Table "revert"
       Column       |  Type   | Modifiers 
--------------------+---------+-----------
 page_id            | integer | 
 revision_id        | integer | 
 reverted_to        | integer | 
Indexes:
    "revert_page_between_idx" btree (page_id, reverted_to, revision_id) CLUSTER
Run Code Online (Sandbox Code Playgroud)

该表包含恢复修订版(约2200万行).如果已恢复修订,则该revision_id将在revision_main表中有一行,其revision_id将在reverted_to和revision_id之间,并共享相同的page_id.(如果你很好奇,请参阅http://en.wikipedia.org/wiki/Wikipedia:Revert.)

加入这两个表以获得恢复的修订似乎很简单.这是我提出的:

explain SELECT
    r.revision_id,
    rvt.revision_id
FROM revision_main r
INNER JOIN revert rvt 
    ON r.page_id = rvt.page_id 
    AND r.revision_id > rvt.reverted_to
    AND r.revision_id < rvt.revision_id;
                                       QUERY PLAN                                               
----------------------------------------------------------------------------------------------------
 Merge Join  (cost=4202878.87..15927491478.57 rows=88418194298 width=8)
   Merge Cond: (r.page_id = rvt.page_id)
   Join Filter: ((r.revision_id > rvt.reverted_to) AND (r.revision_id < rvt.revision_id))
   ->  Index Scan using revision_main_page_id_idx on revision_main r  (cost=0.00..9740790.61 rows=223163392 width=8)
   ->  Materialize  (cost=4201592.06..4536465.21 rows=26789852 width=12)
         ->  Sort  (cost=4201592.06..4268566.69 rows=26789852 width=12)
               Sort Key: rvt.page_id
               ->  Seq Scan on revert rvt  (cost=0.00..438534.52 rows=26789852 width=12)
Run Code Online (Sandbox Code Playgroud)

即使revert上的聚集索引应该是Btree索引(因此支持比较运算符,如"<"和">"),查询优化器不会使用连接索引,"explain"预测总成本超过15十亿(可能在明年完成).

比较运算符是否无法与多列(btree)索引一起使用?我只是做错了吗?

bti*_*lly 5

看起来优化器比你更了解它的工作.

如果您选择的不只是表的一小部分(依赖于硬件的分数,假设为5%),则选择和排序整个表的速度比使用索引要快.如果您只是选择几行,那么它应该使用索引.因此它为您提供了正确的数据查询计划.

至于总成本,这些数字都是BS,仅在单个查询中相互比较时才有用.(两个非常相似的查询产生的总成本可能是非常不同的.)执行时间和查询成本几乎无关.