mydb=# select * from pg_am; oid | amname | amhandler | amtype ------+--------+----------------------+-------- 2 | heap | heap_tableam_handler | t 403 | btree | bthandler | i 405 | hash | hashhandler | i 783 | gist | gisthandler | i 2742 | gin | ginhandler | i 4000 | spgist | spghandler | i 3580 | brin | brinhandler | i(7 rows) 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)clusterable:可以根据索引对表的行重新排序,直接使用cluster命令,语法如下:
mydb=# \h cluster Command: CLUSTERDescription: cluster a table according to an indexSyntax:CLUSTER [VERBOSE] table_name [ USING index_name ]CLUSTER [VERBOSE]URL: https://www.postgresql.org/docs/13/sql-cluster.htmlselect p.name, pg_index_column_has_property(‘tbl_a_pkey‘::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)除了需要知道各种操作方法相关的属性之外,我们还需要知道各种不同的操作方法分别支持哪些数据类型和哪些运算符。pg中提供了操作符类和操作符族的概念。
操作符类包含用于索引的最小运算符集(可能还有辅助函数),以操作某种数据类型。
某些操作符族中包括一个操作符类别。此外,如果一个通用的运算符族具有相同的语义,则它们可以包含多个运算符类。例如,integer_ops系列包括类型bigint,integer和smallint的int8_ops,int4_ops和int2_ops类,它们的大小不同但含义相同
--如整型和日期为例select opfname, opcname, opcintype::regtypefrom pg_opclass opc, pg_opfamily opfwhere opf.opfname = ‘integer_ops‘and opc.opcfamily = opf.oidand 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系列包含用于操作日期(有时间和无时间)的运算符类:select opfname, opcname, opcintype::regtypefrom pg_opclass opc, pg_opfamily opfwhere opf.opfname = ‘datetime_ops‘and opc.opcfamily = opf.oidand 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操作:==
explain select * from t where b like ‘A%‘;--这种情况我们就可以通过使用操作符类 text_pattern_ops创建索引来克服此限制:create index on t(b text_pattern_ops);我们可以通过查询这些系统目录解决很多问题,例如:某种访问方法可以操纵哪些数据类型:
btree方法可以操作以下数据类型
select opcname, opcintype::regtypefrom pg_opclasswhere opcmethod = (select oid from pg_am where amname = ‘btree‘)order by opcintype::regtype::text; opcname | opcintype ---------------------+----------------------------- array_ops | anyarray enum_ops | anyenum range_ops | anyrange int8_ops | bigint bit_ops | bit varbit_ops | bit varying bool_ops | boolean bytea_ops | bytea char_ops | "char" bpchar_pattern_ops | character bpchar_ops | character date_ops | date float8_ops | double precision cidr_ops | inet inet_ops | inet int4_ops | integer interval_ops | interval jsonb_ops | jsonb macaddr_ops | macaddr macaddr8_ops | macaddr8 money_ops | money name_ops | name numeric_ops | numeric oid_ops | oid oidvector_ops | oidvector pg_lsn_ops | pg_lsn float4_ops | real record_image_ops | record record_ops | record int2_ops | smallint varchar_pattern_ops | text text_ops | text varchar_ops | text text_pattern_ops | text tid_ops | tid timestamp_ops | timestamp without time zone timestamptz_ops | timestamp with time zone time_ops | time without time zone timetz_ops | time with time zone tsquery_ops | tsquery tsvector_ops | tsvector uuid_ops | uuid xid8_ops | xid8(43 rows)运算符类包含哪些运算符
select amop.amopopr::regoperatorfrom pg_opclass opc, pg_opfamily opf, pg_am am, pg_amop amopwhere opc.opcname = ‘array_ops‘and opf.oid = opc.opcfamilyand am.oid = opf.opfmethodand amop.amopfamily = opc.opcfamilyand am.amname = ‘btree‘and amop.amoplefttype = opc.opcintype; amopopr ----------------------- <(anyarray,anyarray) <=(anyarray,anyarray) =(anyarray,anyarray) >=(anyarray,anyarray) >(anyarray,anyarray)(5 rows)| 数据字典 | 描述 |
|---|---|
| pg_proc | procedure |
| pg_operator | operator |
| pg_amop | access method’s operator |
| pg_opfamily | operator family |
| pg_amproc | access method’s support procedure |
| pg_type | datatype |
| pg_opclass | operator class |
| pg_am | access method |
--创建一个新的组合类型create type complex as (re float, im float);--创建表create table t1(x complex);insert into t1 values ((0.0, 10.0)), ((1.0, 3.0)), ((1.0, 1.0));insert into t1 values((1.0,2.0)),((2.0,2.0));默认情况,对于组合类型排序是分开的,先比较第一个字段再比较第二个,也可以通过其他方式排序。
--创建相关函数create function modulus(a complex) returns float as $$select sqrt(a.re*a.re + a.im*a.im);$$ immutable language sql;--定义5种操作符函数:create function complex_lt(a complex, b complex) returns boolean as $$select modulus(a) < modulus(b);$$ immutable language sql;create function complex_le(a complex, b complex) returns boolean as $$select modulus(a) <= modulus(b);$$ immutable language sql;create function complex_eq(a complex, b complex) returns boolean as $$select modulus(a) = modulus(b);$$ immutable language sql;create function complex_ge(a complex, b complex) returns boolean as $$select modulus(a) >= modulus(b);$$ immutable language sql;create function complex_gt(a complex, b complex) returns boolean as $$select modulus(a) > modulus(b);$$ immutable language sql;创建对应的操作符
create operator #<#(leftarg=complex, rightarg=complex, procedure=complex_lt);create operator #<=#(leftarg=complex, rightarg=complex, procedure=complex_le);create operator #=#(leftarg=complex, rightarg=complex, procedure=complex_eq);create operator #>=#(leftarg=complex, rightarg=complex, procedure=complex_ge);create operator #>#(leftarg=complex, rightarg=complex, procedure=complex_gt);--比较数字select (1.0,1.0)::complex #<# (1.0,3.0)::complex;除了整个5个操作符,还需要定义函数:小于返回-1;等于返回0;大于返回1。其他访问方法可能需要定义其他函数
create function complex_cmp(a complex, b complex) returns integer as $$select case when modulus(a) < modulus(b) then -1when modulus(a) > modulus(b) then 1else 0end; $$ language sql;创建一个操作符类
create operator class complex_opsdefault for type complexusing btree asoperator 1 #<#,operator 2 #<=#,operator 3 #=#,operator 4 #>=#,operator 5 #>#,function 1 complex_cmp(complex,complex);--查看排序结构mydb=# select * from t1 order by x; x -------- (1,1) (1,3) (0,10)(3 rows)--查看可以使用此查询获取支持的函数:select amp.amprocnum,amp.amproc,amp.amproclefttype::regtype,amp.amprocrighttype::regtypefrom pg_opfamily opf,pg_am am,pg_amproc ampwhere opf.opfname = ‘complex_ops‘and opf.opfmethod = am.oidand am.amname = ‘btree‘and amp.amprocfamily = opf.oid; amprocnum | amproc | amproclefttype | amprocrighttype -----------+-------------+----------------+----------------- 1 | complex_cmp | complex | complex(1 row)管理操作符
--查看 操作符 和操作符类select * from pg_operator;select * from pg_opclass;--查看操作符类型select o.oid,o.oprname, (select t.typname from pg_type t where o.oprleft=t.oid) as oprleft, (select t.typname from pg_type t where o.oprright=t.oid) as oprrightfrom pg_operator o where o.oprname like ‘#%#‘;--删除操作符drop operator #<# (complex,complex);--删除操作类DROP OPERATOR CLASS complex_ops using btree;--删除函数select * from pg_proc where proname like ‘com%‘;drop function function_name;无论哪种扫描类型(index scan、index only scan、bitmap scan),使用btree索引都会返回有序的数据。所以,如果在排序列上存在索引,优化器会首先考虑是索引扫描,否则就是先顺序扫描然后排序。
create index idx_t1 on t1(c1 desc);--尤其组合索引 ,如果常用排序,可使用如下方法create index idx_t1 on t1(c1 desc,c2 asc);pg索引可以存储空值,并支持按条件IS NULL和IS NOT NULL进行搜索。
explain select * from t1 where c1 is null;在索引中null值存储在索引的一端,取决于创建索引时指定nulls first还是nulls last。
如果查询包括排序,则这一点很重要:如果SELECT命令在其ORDER BY子句中指定的NULL顺序与构建索引指定的顺序相同(NULLS FIRST或NULLS LAST),则可以使用索引,否则将无法使用索引。
在数据库中null是无法和其它值进行比较的
PostgreSQL的btree索引的算法可以参考:src/backend/access/nbtree/README
其中PostgreSQL 的B-Tree索引页分为几种类别,我们可以通过btpo_flags的值去区分.
meta page root page # btpo_flags=2 branch page # btpo_flags=0 leaf page # btpo_flags=1 leaf&root page # btpo_flags=3--详情见:src/include/access/nbtree.h/* Bits defined in btpo_flags */#define BTP_LEAF (1 << 0) /* leaf page, i.e. not internal page */#define BTP_ROOT (1 << 1) /* root page (has no parent) */#define BTP_DELETED (1 << 2) /* page has been deleted from tree */#define BTP_META (1 << 3) /* meta-page */#define BTP_HALF_DEAD (1 << 4) /* empty, but still in tree */#define BTP_SPLIT_END (1 << 5) /* rightmost page of split group */#define BTP_HAS_GARBAGE (1 << 6) /* page has LP_DEAD tuples */#define BTP_INCOMPLETE_SPLIT (1 << 7) /* right sibling‘s downlink is missing */其中meta page和root page是必须有的,meta page需要一个页来存储,表示指向root page的page id。
随着记录数的增加,一个root page可能存不下所有的heap item,就会有leaf page,甚至branch page,甚至多层的branch page。
一共有几层branch 和 leaf,就用btree page元数据的 level 来表示。
可以通过pageinspect插件研究所以你内部结构
哈希表是根据键(Key)而直接访问在内存储存位置的数据结构。它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录,这加快了查找速度。这个映射函数称做散列函数,存放记录的数组称做哈希表
当插入索引时,让我们计算键的哈希函数。PostgreSQL中的哈希函数总是返回integer类型,其范围为2的32次方≈40亿个值。存储桶的数量最初等于2,然后根据数据大小动态增加。bucket编号可以使用位算法从哈希码中计算出来。这是我们将放置ctid的bucket。
当搜索索引时,我们计算键的哈希函数并获取bucket编号。现在,仍然需要遍历bucket的内容,并仅返回具有适当哈希码的匹配ctid。由于存储的“hash code - ctid”对是有序的,因此可以高效地完成此操作。
哈希索引包含4种页:meta page, primary bucket page, overflow page, bitmap page
注意bucket, page都没有提供收缩功能,即无法从OS中收缩空间,但是提供了reuse(通过bitmap page跟踪),如果想要减小索引大小的唯一办法就是使用REINDEX或VACUUM FULL命令从头开始重建索引
hash索引介绍:
src/backend/access/hash/README
使用场景:
使用限制:
原文:https://www.cnblogs.com/chenguopa/p/15228699.html