PostgreSQL之索引(二)索引使用

操作符类和操作符族

  一个索引定义可以为索引中的每一列都指定一个操作符类。

CREATE INDEX name ON table (column opclass [sort options] [, ...]);

  比如,可以在创建B-tree索引时通过ASCDESCNULLS FIRSTNULLS LAST选项来改变索引的排序

CREATE INDEX test3_desc_index ON test3 (id DESC NULLS LAST);

 组合多个索引

  PostgreSQL具有组合多个索引(包括多次使用同一个索引)的能力来处理那些不 能用单个索引扫描实现的情况。系统能在多个索引扫描之间安排ANDOR条件。例如, WHERE x = 42 OR x = 47 OR x = 53 OR x = 99这样一个查询可以被分解成为四个独立的在x上索引扫描,每一个扫描使用其中一个条件。这些查询的结果将被“或”起来形成最后的结果。。另一个例子是如果我们在xy上都有独立的索引,WHERE x = 5 AND y = 6这样的查询的一种可能的实现方式就是分别使用两个索引配合相应的条件,然后将结果“与”起来得到最后的结果行。

  为了组合多个索引,系统扫描每一个所需的索引并在内存中准备一个位图用于指示表中符合索引条件的行的位置。然后这些位图会被根据查询的需要“与”和“或”起来。最后,实际的表行将被访问并返回。表行将被以物理顺序访问,因为位图就是以这种顺序布局的。这意味着原始索引中的任何排序都会被丢失,并且如果存在一个ORDER BY子句就需要一个单独的排序步骤。由于这个原因以及每一个附加的索引都需要额外的时间,即使有额外的索引可用,规划器有时也会选择使用单一索引扫描。

表达式索引

  一个索引列并不一定是底层表的一个列,也可以是从表的一列或多列计算而来的一个函数或者标量表达式。索引表达式的维护代价较为昂贵,因为在每一个行被插入或更新时都得为它重新计算相应的表达式。然而,索引表达式在进行索引搜索时却需要重新计算,因为它们的结果已经被存储在索引中了。

SELECT * FROM people WHERE (first_name || ' ' || last_name) = 'John Smith';
CREATE INDEX people_names ON people ((first_name || ' ' || last_name));

部分索引

  一个部分索引是建立在表的一个子集上,而该子集则由一个条件表达式(被称为部分索引的谓词)定义。而索引中只包含那些符合该谓词的表行的项。部分索引是一种专门的特性,但在很多种情况下它们也很有用。
  使用部分索引的一个主要原因是避免索引公值。由于搜索一个公值的查询(一个在所有表行中占比超过一定百分比的值)不会使用索引,所以完全没有理由将这些行保留在索引中。这可以减小索引的尺寸,同时也将加速使用索引的查询。它也将加速很多表更新操作,因为这种索引并不需要在所有情况下都被更新。

CREATE TABLE tests (
    subject text,
    target text,
    success boolean,
    ...
);

CREATE UNIQUE INDEX tests_success_constraint ON tests (subject, target)
    WHERE success;

覆盖索引

  PostgreSQL中的所有索引是二级索引,这意味着每个索引都是与表的主数据区(在PostgreSQL术语称为表的堆中)分开存储。这意味着在普通索引扫描中,每行检索都需要从索引和堆中取数据。为了解决这种性能问题,PostgreSQL支持只用索引的扫描,这类扫描可以仅用一个索引来回答查询而不产生任何堆访问。其基本思想是直接从每一个索引项中直接返回值,而不是去参考相关的堆项。
  在使用这种方法时有两个根本的限制:
  1.索引类型必须支持只用索引的扫描。B-树索引总是支持只用索引的扫描。GiST 和 SP-GiST 索引只对某些操作符类支持只用索引的扫描。其他索引类型不支持这种扫描。底层的要求是索引必须在物理上存储或者可以重构出每一个索引项对应的原始数据值。GIN 索引是一个不支持只用索引的扫描的反例,因为它的每一个索引项通常只包含原始数据值的一部分。
  2.查询必须只引用存储在该索引中的列。
  为了有效利用仅索引扫描功能,可以选择创建一个覆盖索引,它是一个特别设计的索引,包含经常运行的特殊类型查询所需要的列。由于查询通常需要检索的列不仅仅是他们搜索的列,PostgreSQL允许您创建索引,这个索引中有些列只是“负荷”而不是搜索键的一部分。这可以通过添加INCLUDE来完成子句来列出了额外的列。

SELECT y FROM tab WHERE x = 'key';
CREATE INDEX tab_x_y ON tab(x) INCLUDE (y);
原文地址:https://www.cnblogs.com/ryjJava/p/14359592.html