PostgreSQL码农集散地

PostgreSQL 18 preview - 泛化索引AM排序接口, 消除btree依赖

PostgreSQL 18 preview - 泛化索引AM排序接口, 消除btree依赖

说起排序, 你首先想到的肯定是btree索引, 因为hash, gin, brin, bloom都不支持排序, gist, sp-gist支持按距离排序, hnsw支持按向量距离排序.

为什么索引能支持排序呢? 目前要让新的索引AM支持排序, 有什么依赖?

PrepareSortSupportFromIndexRel() 是一个用于准备排序支持(SortSupport)的函数,它根据索引关系(Index Relation)的信息来初始化排序相关的参数。

在之前的实现中,它通过 B-tree 策略号(strategy number)来判断排序方向(正向或反向),这导致了对 B-tree 索引的硬编码依赖。

为了解决这个依赖, 来看看这个patch.

https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=a359d3701991d040bf7b66cfa7052546eb923c38

Simplify and generalize PrepareSortSupportFromIndexRel()    
author Peter Eisentraut <[email protected]>     
Fri, 14 Mar 2025 09:34:08 +0000 (10:34 +0100)    
committer Peter Eisentraut <[email protected]>     
Fri, 14 Mar 2025 09:34:08 +0000 (10:34 +0100)    
commit a359d3701991d040bf7b66cfa7052546eb923c38    
tree 2d22e60a2d991fc36f085aab87a07789afad5cd2 tree    
parent 1548c3a30436dd825cfbf57923c6766b2fddd355 commit | diff    
Simplify and generalize PrepareSortSupportFromIndexRel()    

PrepareSortSupportFromIndexRel() was accepting btree strategy numbers    
purely for the purpose of comparing it later against btree strategies    
to determine if the sort direction was forward or reverse.  Change    
that.  Instead, pass a bool directly, to indicate the same without an    
unfortunate assumption that a strategy number refers specifically to a    
btree strategy.  (This is similar in spirit to commits 0d2aa4d4937 and    
c594f1ad2ba.)    

(This could arguably be simplfied further by having the callers fill    
in ssup_reverse directly.  But this way, it preserves consistency by    
having all PrepareSortSupport*() variants be responsible for filling    
in ssup_reverse.)    

Moreover, remove the hardcoded check against BTREE_AM_OID, and check    
against amcanorder instead, which is the actual requirement.    

Co-authored-by: Mark Dilger <[email protected]>    
Discussion: https://www.postgresql.org/message-id/flat/[email protected]    

AI解读 Simplify and generalize PrepareSortSupportFromIndexRel() 的 Patch

这个 Patch 的主要目的是简化和泛化 PrepareSortSupportFromIndexRel() 函数,使其更加清晰、灵活,并减少对特定索引类型(如 B-tree)的依赖。以下是详细的解读:

1. 背景

PrepareSortSupportFromIndexRel() 是一个用于准备排序支持(SortSupport)的函数,它根据索引关系(Index Relation)的信息来初始化排序相关的参数。在之前的实现中,它通过 B-tree 策略号(strategy number)来判断排序方向(正向或反向),这导致了对 B-tree 索引的硬编码依赖。

2. 问题

  • 对 B-tree 策略号的依赖:函数通过 B-tree 策略号来判断排序方向,这隐含地假设了所有索引类型都使用 B-tree 的策略号。这种设计不够通用,也不符合其他索引类型(如 GiST、GIN 等)的需求。
  • **硬编码检查 BTREE_AM_OID**:函数直接检查索引是否是 B-tree 类型(通过 BTREE_AM_OID),而不是检查索引是否支持排序(通过 amcanorder)。这限制了函数的适用范围。

3. Patch 的改进

Patch 对 PrepareSortSupportFromIndexRel() 进行了以下改进:

(1) 用 bool 替换 B-tree 策略号
  • 原实现:通过 B-tree 策略号(如 BTLessStrategyNumber 或 BTGreaterStrategyNumber)来判断排序方向。
  • 新实现:直接传递一个 bool 参数(如 reverse)来明确指定排序方向,而不是依赖于 B-tree 策略号。
  • 优点:
    • 减少了对 B-tree 索引的依赖,使函数更加通用。
    • 代码更清晰,逻辑更直接。
(2) 移除对 BTREE_AM_OID 的硬编码检查
  • 原实现:直接检查索引是否是 B-tree 类型(通过 BTREE_AM_OID)。
  • 新实现:检查索引是否支持排序(通过 amcanorder)。
  • 优点:
    • 使函数适用于所有支持排序的索引类型,而不仅仅是 B-tree。
    • 更符合索引的实际能力,而不是特定类型。
(3) 保持一致性
  • Patch 保留了 PrepareSortSupportFromIndexRel() 对 ssup_reverse 的初始化职责,而不是让调用者直接设置 ssup_reverse。这样做是为了保持所有 PrepareSortSupport*() 函数的一致性。

4. 代码示例

以下是 Patch 修改前后的代码对比:

修改前
voidPrepareSortSupportFromIndexRel(Relation indexRel, int16 strategy){    
if (indexRel->rd_rel->relam != BTREE_AM_OID)    
        elog(ERROR, "only B-tree indexes are supported");    

    ssup->ssup_reverse = (strategy == BTGreaterStrategyNumber);    
}    
修改后
voidPrepareSortSupportFromIndexRel(Relation indexRel, bool reverse){    
if (!indexRel->rd_amroutine->amcanorder)    
        elog(ERROR, "index does not support ordering");    

    ssup->ssup_reverse = reverse;    
}    

5. 影响和意义

  • 通用性:函数现在可以适用于所有支持排序的索引类型,而不仅仅是 B-tree。
  • 清晰性:通过 bool 参数明确指定排序方向,代码更易读、更易维护。
  • 一致性:保留了 PrepareSortSupport*() 函数对 ssup_reverse 的初始化职责,避免了逻辑分散。

6. 相关 Commit

Patch 提到了两个相关的 Commit:

  • 0d2aa4d4937 和 c594f1ad2ba:这些 Commit 也涉及减少对 B-tree 策略号的依赖,使代码更加通用。Patch 延续了这种设计思想。

7. 总结

这个 Patch 通过以下方式改进了 PrepareSortSupportFromIndexRel():

  1. 用 bool 替换 B-tree 策略号,减少对 B-tree 的依赖。
  2. 移除对 BTREE_AM_OID 的硬编码检查,改用 amcanorder 检查索引是否支持排序。
  3. 保持 PrepareSortSupport*() 函数的一致性。

这些改进使函数更加通用、清晰,并符合 PostgreSQL 的设计哲学。对于 DBA 和开发者来说,这意味着代码更易维护,同时支持更多的索引类型和场景。