介面
在
第一篇文章中 ,我们提到了访问方法必须提供有关其自身的信息。 让我们看一下访问方法接口的结构。
物产
访问方法的所有属性都存储在“ pg_am”表中(“ am”代表访问方法)。 我们还可以从同一张表中获得可用方法的列表:
postgres=# select amname from pg_am;
amname -------- btree hash gist gin spgist brin (6 rows)
尽管可以合理地将顺序扫描称为访问方法,但出于历史原因,它不在此列表中。
在PostgreSQL 9.5和更低的版本中,每个属性都用“ pg_am”表的单独字段表示。 从9.6版开始,使用特殊功能查询属性,并将其分为几层:
- 访问方法属性-“ pg_indexam_has_property”
- 特定索引的属性-“ pg_index_has_property”
- 索引的各个列的属性-“ pg_index_column_has_property”
展望未来,访问方法层和索引层是分开的:到目前为止,所有基于一种访问方法的索引将始终具有相同的属性。
以下四个属性是访问方法的属性 (以“ btree”为例):
postgres=# select a.amname, p.name, pg_indexam_has_property(a.oid,p.name) from pg_am a, unnest(array['can_order','can_unique','can_multi_col','can_exclude']) p(name) where a.amname = 'btree' order by a.amname;
amname | name | pg_indexam_has_property --------+---------------+------------------------- btree | can_order | t btree | can_unique | t btree | can_multi_col | t btree | can_exclude | t (4 rows)
- can_order。
访问方法使我们能够在创建索引时指定值的排序顺序(到目前为止仅适用于“ btree”)。 - can_unique
支持唯一约束和主键(仅适用于“ btree”)。 - can_multi_col。
索引可以建立在几列上。 - can_exclude
支持排除约束EXCLUDE。
以下属性与索引有关 (例如,让我们考虑现有
索引 ):
postgres=# select p.name, pg_index_has_property('t_a_idx'::regclass,p.name) from unnest(array[ 'clusterable','index_scan','bitmap_scan','backward_scan' ]) p(name);
name | pg_index_has_property ---------------+----------------------- clusterable | t index_scan | t bitmap_scan | t backward_scan | t (4 rows)
- 可集群的。
可以根据索引对行进行重新排序(使用同名命令CLUSTER进行群集)。 - index_scan。
支持索引扫描。 尽管此属性看起来很奇怪,但并非所有索引都能一次返回TID-有些返回结果一次全部返回,并且仅支持位图扫描。 - 位图扫描。
支持位图扫描。 - 向后扫描。
可以按建立索引时指定的相反顺序返回结果。
最后,以下是列属性: postgres=# select p.name, pg_index_column_has_property('t_a_idx'::regclass,1,p.name) from unnest(array[ 'asc','desc','nulls_first','nulls_last','orderable','distance_orderable', 'returnable','search_array','search_nulls' ]) p(name);
name | pg_index_column_has_property --------------------+------------------------------ asc | t desc | f nulls_first | f nulls_last | t orderable | t distance_orderable | f returnable | t search_array | t search_nulls | t (9 rows)
- asc,desc,nulls_first,nulls_last,可排序。
这些属性与值的排序有关(当我们到达“ btree”索引的描述时将讨论它们)。 - distance_orderable。
可以按照操作确定的排序顺序返回结果(到目前为止仅适用于GiST和RUM索引)。 - 可退还
在不访问表的情况下使用索引的可能性,即仅索引扫描的支持。 - search_array。
支持使用表达式“ indexed-field IN( list_of_constants )”搜索多个值,该表达式与“ indexed-field = ANY( array_of_constants )”相同。 - search_nulls。
通过IS NULL和IS NOT NULL条件进行搜索的可能性。
我们已经详细讨论了一些属性。 一些属性特定于某些访问方法。 在考虑这些特定方法时,我们将讨论这些属性。
操作员类别和家庭
除了所描述的接口公开的访问方法的属性之外,还需要信息来了解访问方法接受哪些数据类型和哪些运算符。 为此,PostgreSQL引入了
操作符类和
操作符族的概念。
运算符类包含用于索引的最小运算符集(可能还有辅助函数),以操作某种数据类型。
某些操作员家族中包括一个操作员类别。 此外,如果一个通用的运算符族具有相同的语义,则它们可以包含多个运算符类。 例如,“ integer_ops”家族包括“ bigint”,“ integer”和“ smallint”类型的“ int8_ops”,“ int4_ops”和“ int2_ops”类,它们的大小不同,但含义相同:
postgres=# select opfname, opcname, opcintype::regtype from pg_opclass opc, pg_opfamily opf where opf.opfname = 'integer_ops' and opc.opcfamily = opf.oid and opf.opfmethod = ( select oid from pg_am where amname = 'btree' );
opfname | opcname | opcintype -------------+----------+----------- integer_ops | int2_ops | smallint integer_ops | int4_ops | integer integer_ops | int8_ops | bigint (3 rows)
另一个示例:“ datetime_ops”家族包括用于操作日期(有时间和无时间)的运算符类:
postgres=# select opfname, opcname, opcintype::regtype from pg_opclass opc, pg_opfamily opf where opf.opfname = 'datetime_ops' and opc.opcfamily = opf.oid and opf.opfmethod = ( select oid from pg_am where amname = 'btree' );
opfname | opcname | opcintype --------------+-----------------+----------------------------- datetime_ops | date_ops | date datetime_ops | timestamptz_ops | timestamp with time zone datetime_ops | timestamp_ops | timestamp without time zone (3 rows)
运算符家族还可以包括其他运算符,以比较不同类型的值。 分组到族中使计划者可以将具有不同类型值的谓词使用索引。 一个家族还可以包含其他辅助功能。
在大多数情况下,我们不需要了解操作员的家庭和类别。 通常,我们只创建索引,默认情况下使用某个运算符类。
但是,我们可以显式指定运算符类。 这是当需要显式规范时的一个简单示例:在排序规则不同于C的数据库中,常规索引不支持LIKE操作:
postgres=# show lc_collate;
lc_collate ------------- en_US.UTF-8 (1 row)
postgres=# explain (costs off) select * from t where b like 'A%';
QUERY PLAN ----------------------------- Seq Scan on t Filter: (b ~~ 'A%'::text) (2 rows)
我们可以通过使用运算符类“ text_pattern_ops”创建索引来克服此限制(请注意计划中的条件如何更改):
postgres=# create index on t(b text_pattern_ops); postgres=# explain (costs off) select * from t where b like 'A%';
QUERY PLAN ---------------------------------------------------------------- Bitmap Heap Scan on t Filter: (b ~~ 'A%'::text) -> Bitmap Index Scan on t_b_idx1 Index Cond: ((b ~>=~ 'A'::text) AND (b ~<~ 'B'::text)) (4 rows)
系统目录
在本文的总结中,我们提供了系统目录中与操作员类和家族直接相关的表的简化图。

不用说,所有这些表
都已详细描述 。
系统目录使我们无需查找文档即可找到许多问题的答案。 例如,某种访问方法可以操纵哪些数据类型?
postgres=# select opcname, opcintype::regtype from pg_opclass where opcmethod = (select oid from pg_am where amname = 'btree') order by opcintype::regtype::text;
opcname | opcintype ---------------------+----------------------------- abstime_ops | abstime array_ops | anyarray enum_ops | anyenum ...
运算符类包含哪些运算符(因此,索引访问可用于包含该运算符的条件)?
postgres=# select amop.amopopr::regoperator from pg_opclass opc, pg_opfamily opf, pg_am am, pg_amop amop where opc.opcname = 'array_ops' and opf.oid = opc.opcfamily and am.oid = opf.opfmethod and amop.amopfamily = opc.opcfamily and am.amname = 'btree' and amop.amoplefttype = opc.opcintype;
amopopr ----------------------- <(anyarray,anyarray) <=(anyarray,anyarray) =(anyarray,anyarray) >=(anyarray,anyarray) >(anyarray,anyarray) (5 rows)
继续阅读 。