使用 INCLUDE 相对于在 INDEX 中添加列来覆盖索引的优势

tuk*_*tuk 6 postgresql index covering-index

Postgres 文档声明了以下有关仅索引扫描和覆盖索引的内容

如果您经常运行类似的查询

SELECT y FROM tab WHERE x = 'key';

加速此类查询的传统方法是仅在 x 上创建索引。然而,索引定义为

CREATE INDEX tab_x_y ON tab(x) INCLUDE (y);

可以将这些查询作为仅索引扫描来处理,因为可以从索引中获取 y 而无需访问堆。

因为列 y 不是索引搜索键的一部分,所以它不必是索引可以处理的数据类型;它仅存储在索引中,并且不被索引机制解释。另外,如果索引是唯一索引,即

CREATE UNIQUE INDEX tab_x_y ON tab(x) INCLUDE (y);

唯一性条件仅适用于 x 列,不适用于 x 和 y 的组合。(INCLUDE 子句也可以用 UNIQUE 和 PRIMARY KEY 约束编写,为设置这样的索引提供替代语法。)

问题1:如果 的数据类型y可以添加到索引中,并且没有唯一性要求,那么使用CREATE INDEX tab_x_y ON tab(x) INCLUDE (y)overCREATE INDEX tab_x_y ON tab(x, y)进行查询有什么优势SELECT y FROM tab WHERE x = 'key';

在向索引添加非键有效负载列(尤其是宽列)时保持保守是明智的做法。如果索引元组超过索引类型允许的最大大小,数据插入将失败。在任何情况下,非键列都会复制索引表中的数据并使索引的大小膨胀,从而可能会减慢搜索速度。

问题2:有人能举例说明什么吗wide columns意思吗?

问题 3:有人能在 的上下文中解释以下陈述吗INCLUDE(y)?如果INCLUDE支持仅索引扫描,那么y也必须存储在索引中。那么下面的陈述为什么不成立呢INCLUDE(y)

在任何情况下,非键列都会复制索引表中的数据并导致索引的大小膨胀

Lau*_*lbe 6

除了埃尔文的出色回答之外,使用INCLUDE语法还有一个额外的优点:文档。

\n

想象一下,您决定需要在(a, b)表的列上建立索引tab。现在你发现已经有索引了(a, c)。在这种情况下,您有两种选择:

\n
    \n
  • 只需继续创建另一个索引

    \n
  • \n
  • 如果您确定该列c只是添加到索引中以支持仅索引扫描并且从未用作搜索条件,则可以删除旧索引并创建新索引(a, b, c),从而保存索引

    \n
  • \n
\n

现在通常很难确定一个索引列从来没有被用作搜索条件,除非 \xe2\x80\x93 很好,除非它出现在子句中INCLUDE。在这种情况下,您不必三思而后行,可以将索引 on 替换(a) INCLUDE (c)为 1 on(a, b) INCLUDE (c)

\n


Erw*_*ter 5

经验法则 1:如果您从不使用索引列进行过滤或排序(或连接,或强制唯一性),您不妨将其移至INCLUDE。没有失去什么,反而得到了一些东西。

经验法则 2:INCLUDE只有当您真正从中获得仅索引扫描时,列才有意义。在某些情况下甚至不是这样。

答案 1:INCLUDE功能主要适用于两种排除的情况:唯一性或索引中不允许的情况。但对于其他情况仍然有一些小好处。该手册进一步解释如下:

后缀截断总是从上层 B 树中删除非键列。作为有效负载列,它们从不用于指导索引扫描。当键列的剩余前缀恰好足以描述最低 B 树级别上的元组时,截断过程还会删除一个或多个尾随键列。实际上,不使用子句覆盖索引INCLUDE通常会避免存储在上层中有效负载的列。但是,将有效负载列显式定义为非键列可以可靠地使上层中的元组保持较小。

现在,B 树索引只有几层深度。但上层是必须一直阅读。保持较小的规模是最有帮助的。即使是很小的效果也会因此而增强。对于大基数(多个索引级别)和少量重复(后缀截断无法弥补未将有效负载列移动到INCLUDE部件的情况)

另外,还有一个带有表达式索引的情况。Postgres 目前(Postgres 15)还不够智能,无法选择仅索引扫描,除非涉及的列本身包含在索引中。再次看一下说明书:

如果仅索引扫描似乎足够值得,则可以通过添加x为包含列来解决此问题,例如

CREATE INDEX tab_f_x ON tab (f(x)) INCLUDE (x);

(除非x查询中也涉及 plain),INCLUDE (x)仅作为查询规划器的尴尬提示,而仅f(x)是实际使用的。

答案 2: “宽”列是大列,这些列占用“磁盘”(现在通常不是“磁盘”)或 RAM 中的大量存储空间。磁盘存储控制必须访问多少数据页才能满足查询,这通常是影响性能的最重要因素。重要的是内部表示,而不是您看到的文本表示。使用pg_column_size()- 进行测试,但请注意“打包”格式(“磁盘上”)的数据大小可能比 RAM 中的数据更紧凑。还有各种管理费用。看:

答案 3:写入成本和臃肿的大小适用INCLUDE(y)于常规索引列。问题是是否要添加 INCLUDE列,这些列在逻辑上始终是可选的。(常规索引列通常不是可选的。)另请参阅答案 1