SP-Gist

SP-Gist和Gist类似,
«SP»是space partitioning(空间划分)。这里的空间通常就是我们通常所说的空间,例如,二维平面。
SP-GiST适用于空间被递归划分为非相交区域的结构。此类包括四叉树,k维树(k-D树)和基数树。

结构介绍

SP-GiST的思想是将值域拆分为非重叠的子域,每个子域又可以拆分。像这样的分区会生成不平衡的树(不像B树和常规的GiST)。

不相交的特性简化了插入和搜索过程方面的决策。另一方面,通常,树是低分支的。例如,四叉树有四个子节点(与B树不同,后者的节点数为数百个),并且深度更大。像这样的树很适合RAM中的工作,但是索引存储在磁盘上,因此,为了减少I / O操,必须将节点塞到页面中,而有效地做到这一点并不容易。此外,由于分支深度的差异,在索引中找不同值所花费的时间可能会有所不同。

这种访问方法与GiST一样,可以处理低级任务(同时进行访问和锁定,日志记录和纯搜索算法),并提供专门的简化接口,以增加对新数据类型和新分区算法的支持。

SP-GiST树的内部节点存储子节点的引用;可以为每个引用定义标签。此外,内部节点存储称为prefix的值。实际上,该值不是必须的前缀;它被视为满足所有子节点的专有谓词。

SP-GiST的叶节点包含索引类型的值和对表行(TID)的引用。索引数据本身(搜索关键字)可以作为值使用,但不是必须的:可以存储缩短的值。

此外,叶节点可以分组为列表。因此,内部节点不仅可以引用一个值,而且可以引用整个列表。

请注意,叶子节点的前缀,标签和值具有各自独立的数据类型。

与GiST中相同,定义搜索的主要函数是一致性函数。该函数为树节点调用,并返回一组子节点,其值与搜索谓词“一致”(通常,以“索引字段运算符表达式”的形式)。对于叶节点,一致性函数确定该节点中的索引值是否满足搜索谓词。

搜索从根节点开始。一致性功能允许找出有意义的子节点。对找到的每个节点重复该算法。搜索是深度优先的。

在物理层面,从I/O操作的角度来看,索引节点被打包到页面中以使节点高效工作。请注意,一个页面可以包含内部节点或者叶子节点,但不能同时包含两者。

下面分别用四叉树,K-D树,基数树举例说明其搜索原理

四叉树

四叉树用于索引平面中的点。核心思想是相对于中心点将区域递归地分为四个部分(也叫象限)。这样索引树的分支深度可以变化,并取决于象限中点的密度。

正如图中所示的样子,示例是通过示例数据库。

首先,我们把一副平面图分割为4个象限。

然后,再继续分割每个象限

然后一直分割到最终需要的分区

接下来我们提供一个详细而简单的示例。查看这个示例中是如何分区的:

第一个图有象限的编号。下面的图展示了了这种情况下的索引结构。每个内部节点最多有四个子节点。如图所示,每个节点都可以用象限编号标记。但是在执行过程中并没有标签,因为存储四个固定数组更为方便,而且其中一些引用可以为空,比如编号为4的象限。

postgres=# create table points(p point);postgres=# insert into points(p) values(point '(1,1)'), (point '(3,2)'), (point '(6,3)'),(point '(5,5)'), (point '(7,8)'), (point '(8,6)');postgres=# create index points_quad_idx on points using spgist(p);

在这种情况下,默认使用«quad_point_ops»运算符类,其中包含以下运算符:

postgres=# select amop.amopopr::regoperator, amop.amopstrategy
from pg_opclass opc, pg_opfamily opf, pg_am am, pg_amop amop
where opc.opcname = 'quad_point_ops'
and opf.oid = opc.opcfamily
and am.oid = opf.opfmethod
and amop.amopfamily = opc.opcfamily
and am.amname = 'spgist'
and amop.amoplefttype = opc.opcintype;amopopr     | amopstrategy
-----------------+--------------<<(point,point) |            1  strictly left>>(point,point) |            5  strictly right~=(point,point) |            6  coincides<^(point,point) |           10  strictly below>^(point,point) |           11  strictly above<@(point,box)   |            8  contained in rectangle
(6 rows)

例如,让我们看一下, select * from points where p >^ point ‘(2,7)’ 这个查询语句是如何查找的。

首先从根节点开始,并使用一致性函数选择要下降到的子节点。对于运算符> ^,此函数将点(2,7)与中心节点(4,4)的进行比较,并选择可能包含所寻找点的象限,在这种情况下,y轴7>4,会选择会选择第一和第四象限。

在第一象限相对应的节点中,我们再次使用一致性函数确定子节点。中心点是(6,6),我们再次需要从第一和第四象限寻找。


叶节点(8,6)和(7,8)的列表对应于第一象限,其中只有点(7,8)满足查询条件。第四象限为空。

在内部节点(4,4)中,第四象限的引用也为空,这样就完成了搜索。

postgres=# set enable_seqscan = off;postgres=# explain (costs off) select * from points where p >^ point '(2,7)';QUERY PLAN
------------------------------------------------Index Only Scan using points_quad_idx on pointsIndex Cond: (p >^ '(2,7)'::point)
(2 rows)
内部信息

我们可以使用 gevel插件来窥探SP-GiST索引的内部结构。可以看到有2个函数。

demo=# \df *spgist*List of functionsSchema |     Name     | Result data type | Argument data types | Type
--------+--------------+------------------+---------------------+------public | spgist_print | SETOF record     | text                | funcpublic | spgist_stat  | text             | text                | func
demo=# create index airports_coordinates_quad_idx on airports_ml using spgist(coordinates);

可以获取索引的统计信息

demo=# select * from spgist_stat('airports_coordinates_quad_idx');spgist_stats
----------------------------------totalPages:        33           +deletedPages:      0            +innerPages:        3            +leafPages:         30           +emptyPages:        2            +usedSpace:         201.53 kbytes+usedInnerSpace:    2.17 kbytes  +usedLeafSpace:     199.36 kbytes+freeSpace:         61.44 kbytes +fillRatio:         76.64%       +leafTuples:        5993         +innerTuples:       37           +innerAllTheSame:   0            +leafPlaceholders:  725          +innerPlaceholders: 0            +leafRedirects:     0            +innerRedirects:    0
(1 row)

可以通过另外一个函数获取索引树:

demo=# select tid, n, level, tid_ptr, prefix, leaf_value
from spgist_print('airports_coordinates_quad_idx') as t(tid tid,allthesame bool,n int,level int,tid_ptr tid,prefix point,    -- prefix typenode_label int,  -- label type (unused here)leaf_value point -- list value type
)
order by tid, n;tid   | n | level | tid_ptr |      prefix      |    leaf_value
---------+---+-------+---------+------------------+------------------(1,1)   | 0 |     1 | (5,3)   | (-10.220,53.588) |(1,1)   | 1 |     1 | (5,2)   | (-10.220,53.588) |(1,1)   | 2 |     1 | (5,1)   | (-10.220,53.588) |(1,1)   | 3 |     1 | (5,14)  | (-10.220,53.588) |(3,68)  |   |     3 |         |                  | (86.107,55.270)(3,70)  |   |     3 |         |                  | (129.771,62.093)(3,85)  |   |     4 |         |                  | (57.684,-20.430)(3,122) |   |     4 |         |                  | (107.438,51.808)(3,154) |   |     3 |         |                  | (-51.678,64.191)(5,1)   | 0 |     2 | (24,27) | (-88.680,48.638) |(5,1)   | 1 |     2 | (5,7)   | (-88.680,48.638) |...

但是请记住,«spgist_print»不会输出所有叶子节点的值,而只会输出列表中的第一个叶子的值,因此这里只显示索引的结构而不会显示全部内容。

K维树

对于平面中的点,我们还有另一种划分空间的方法。
让我们通过被索引的第一个点画一条水平线。它将平面分为两部分:上部和下部。要索引的第二点分别属于这两个部分。然后,让我们画一条垂直线,将这两个部分再分为两部分:右和左。我们再次通过下一个点画一条水平线,并通过下一个点再画一条垂直线,依此类推。

以这种方式构建的树的所有内部节点将只有两个子节点。这两个引用中的每一个都可以指向层次结构中下一个内部节点或叶节点列表。

这种方法可以很容易地推广到k维空间,因此,这些树在文献中也称为k维(k-D树)。

首先将这个平面分为上不两部分

然后我们再分离上下两部分,分别分为左和右

以此类推,分为最终的想要的分区象限。

要想这样使用分区,我们需要在创建索引时明确指定运算符类“ kd_point_ops”。

postgres=# create index points_kd_idx on points using spgist(p kd_point_ops);
内部结构

在浏览树结构时,需要考虑到在这种情况下,前缀只是一个坐标而不是一个点:

demo=# select tid, n, level, tid_ptr, prefix, leaf_value
from spgist_print('airports_coordinates_kd_idx') as t(tid tid,allthesame bool,n int,level int,tid_ptr tid,prefix float,    -- prefix typenode_label int,  -- label type (unused here)leaf_value point -- list node type
)
order by tid, n;tid   | n | level | tid_ptr |   prefix   |    leaf_value
---------+---+-------+---------+------------+------------------(1,1)   | 0 |     1 | (5,1)   |     53.740 |(1,1)   | 1 |     1 | (5,4)   |     53.740 |(3,113) |   |     6 |         |            | (-7.277,62.064)(3,114) |   |     6 |         |            | (-85.033,73.006)(5,1)   | 0 |     2 | (5,12)  |    -65.449 |(5,1)   | 1 |     2 | (5,2)   |    -65.449 |(5,2)   | 0 |     3 | (5,6)   |     35.624 |(5,2)   | 1 |     3 | (5,3)   |     35.624 |...
基数树(radix tree)

我们还可以使用SP-GiST为字符串实现基数树。基数树的想法是要索引的字符串没有完全存储在叶节点中,而是通过将存储在该节点上方的节点中的值连接到根来获得的。
假设,我们需要索引以下站点:«postgrespro.ru», «postgrespro.com», «postgresql.org», «planet.postgresql.org».

create table sites(url text);insert into sites values ('postgrespro.ru'),('postgrespro.com'),('postgresql.org'),('planet.postgresql.org');create index on sites using spgist(url);

树结构如下:

树的内部节点存储所有子节点共有的前缀。例如,在«stgres»的子节点中,值以«p»+«o»+«stgres»开头。
与四叉树不同,指向子节点的每个指针都另外用一个字符标记(更确切地说,用两个字节标记,但这并不那么重要)。
«text_ops»运算符类支持类似B树的运算符:«equal», «greater», «less»:

select amop.amopopr::regoperator, amop.amopstrategy
from pg_opclass opc, pg_opfamily opf, pg_am am, pg_amop amop
where opc.opcname = 'text_ops'
and opf.oid = opc.opcfamily
and am.oid = opf.opfmethod
and amop.amopfamily = opc.opcfamily
and am.amname = 'spgist'
and amop.amoplefttype = opc.opcintype;amopopr     | amopstrategy
-----------------+--------------~<~(text,text)  |            1~<=~(text,text) |            2=(text,text)    |            3~>=~(text,text) |            4~>~(text,text)  |            5<(text,text)    |           11<=(text,text)   |           12>=(text,text)   |           14>(text,text)    |           15
(9 rows)

带波浪号的运算符的区别在于,它们操作字节而不是字符。
有时,以基数树的形式表示的结果可能会比B树要紧凑得多,因为这些值并未完全存储,而是随着在树中下降时的需要而重构。

如select * from sites where url like ‘postgresp%ru’,可能使用以下索引执行

set enable_seqscan = off;
explain (costs off) select * from sites where url like 'postgresp%ru';QUERY PLAN
------------------------------------------------------------------------------Index Only Scan using sites_url_idx on sitesIndex Cond: ((url ~>=~ 'postgresp'::text) AND (url ~<~ 'postgresq'::text))Filter: (url ~~ 'postgresp%ru'::text)
(3 rows)

实际上,索引查找了大于或等于“ postgresp”但小于“ postgresq”(索引条件)的值,然后从结果中选择匹配值(过滤器)。

首先,通过一致性函数确定我们需要下降到哪个子节点。有两个选项:«p»+«l»(无需下降)和«p»+«o»+«stgres»(继续下降)。
对于«stgres»节点,再次需要调用一致性函数以​​检查«postgres»+«p»+«ro.» (继续下降)和«postgres»+«q»(无需下降)。
对于«ro.»节点及其所有子叶节点,一致性函数将响应“yes”,因此索引方法将返回两个值:“ postgrespro.com”和“ postgrespro.ru”。最后在过滤阶段将选择一个匹配值postgrespro.ru。

内部结构
select * from spgist_print('sites_url_idx') as t(tid tid,allthesame bool,n int,level int,tid_ptr tid,prefix text,         -- prefix typenode_label smallint, -- label typeleaf_value text      -- leaf node type
)
order by tid, n;
SP-Gist相关属性
 amname |     name      | pg_indexam_has_property
--------+---------------+-------------------------spgist | can_order     | fspgist | can_unique    | fspgist | can_multi_col | fspgist | can_exclude   | t

SP-GiST索引不支持排序和唯一性约束。此外,不能在多列上创建索引(与GiST不同)。但是允许使用此类索引来支持排它约束。

以下为索引属性:

     name      | pg_index_has_property
---------------+-----------------------clusterable   | findex_scan    | tbitmap_scan   | tbackward_scan | f

与GiST的区别在于,不可以根据索引重新排序。

以下为列相关的属性:

        name        | pg_index_column_has_property
--------------------+------------------------------asc                | fdesc               | fnulls_first        | fnulls_last         | forderable          | fdistance_orderable | freturnable         | tsearch_array       | fsearch_nulls       | t

不支持排序。到目前为止,SP-GiST不提供用于搜索最近邻居的距离运算符。
SP-GiST可用于仅索引扫描,至少可以用于以上讨论的操作符。如我们所见,在某些情况下,索引值明确的存储在叶节点中,而在另一些情况下,索引值在树下降过程中部分被重建。

NULLs

为了以上示例更加简单化,到目前为止,我们还没有提到NULL。从上面列的属性可以看出,是支持NULL操作。

postgres=# explain (costs off)
select * from sites where url is null;QUERY PLAN
----------------------------------------------Index Only Scan using sites_url_idx on sitesIndex Cond: (url IS NULL)
(2 rows)

Postgresql SP-Gist索引相关推荐

  1. 关于PostgreSQL的GiST索引之四

    3. hstore的GiST索引 hstore的GiST索引实现和全文检索的tsvector的GiST索引的实现差不过,都是签名文件索引. 3.1 GiST索引项的存储 1)所有索引项都采用签名向量压 ...

  2. PostgreSQL中的索引—5(GiST)上

    在之前的文章中,我们讨论了PostgreSQL索引引擎.访问方法的接口,以及两种访问方法:哈希索引和B树.在本文中,我们将描述GiST索引. GiST GiST是"广义搜索树"的缩 ...

  3. PostgreSQL 10.1 手册_部分 II. SQL 语言_第 12 章 全文搜索_12.9. GIN 和 GiST 索引类型

    12.9. GIN 和 GiST 索引类型 有两种索引可以被用来加速全文搜索.注意全文搜索并非一定需要索引,但是在一个定期会被搜索的列上,通常需要有一个索引. CREATE INDEX name ON ...

  4. postgreSQL源码分析——索引的建立与使用——GIST索引(3)

    2021SC@SDUSC 本篇博客主要讲解GiST索引查询的相关函数,并结合具体实例来介绍GIST的使用过程 目录 GIST索引查询 GISTSearchHeapItem GISTSearchItem ...

  5. postgreSQL源码分析——索引的建立与使用——GIST索引(2)

    2021SC@SDUSC 本篇博客主要讲解GiST索引创建以及删除的相关函数 这里写目录标题 GIST创建 相关数据结构 GISTBuildState GISTInsertStack gistbuil ...

  6. postgreSQL源码分析——索引的建立与使用——GIST索引(1)

    2021SC@SDUSC 这一篇博客主要讲解GIST索引的相关的介绍,组织结构以及原理的讲解. 目录 GIST 简介 介绍 扩展性 实现 typedef struct GISTSTATE GIST的索 ...

  7. Postgresql杂谈 09—Postgresql中的Gist索引的深入学习

    本文,我们进一步学习下Gist索引.Gist是Generalized Search Tree的意思,意思是通用搜索树,底层结构也是一种平衡树,它是一套索引模板,可以支持用户实现自定义的索引.相比于BT ...

  8. PostgreSQL中的索引—5(GiST)下

    接上一篇 目录 "btree_gist"扩展 用于全文搜索的RD树 RD-trees 示例 内部构件 属性 其他数据类型 "btree_gist"扩展 让我们把 ...

  9. PostgreSQL索引详解5——Gist索引

    1.概述 Gist(Generalized Search Tree),即通用搜索树.和btree一样,也是平衡的搜索树. 和btree不同的是,btree索引常常用来进行例如大于.小于.等于这些操作中 ...

  10. PostgreSql索引(B-tree索引 Hash索引 GiST索引 SP-GiST索引 GIN 索引 BRIN 索引)

    索引 语法: CREATE INDEX test1_id_index ON test1 (id); 索引的名字test1_id_index可以自由选择,但我们最好选择一个能让我们想起该索引用途的名字. ...

最新文章

  1. 浅谈创业性公司的发展
  2. java常见的内存泄漏
  3. Unofficial Windows Binaries for Python Extension Packages
  4. 【junit】junit4单元测试eclipse
  5. 模拟产品展示 Flash无法展示的追踪过程
  6. python数组遍历输出所有组合_python遍历列表和数组实例讲解
  7. 解决 U盘安装Windows Server 2012 R2 报错 Windows 无法打开所需的文件 Sources\install.wim...
  8. (C/C++学习笔记)附页: C/C++变量的存储类型
  9. 三星a9s参数_三星A9s配置怎么样 三星A9s参数配置介绍
  10. 仅当使用了列列表并且 IDENTITY_INSERT 为 ON 时,才能为表't_ArticleFiles'中的标识列指定显式值。...
  11. mysql gitd 数据结构同步失败_mysql 5.7 gtid主从同步错误修复
  12. java 二进制乱码_深入解析java乱码
  13. qca9535 tftp32 刷机_【U-Boot】U-Boot 刷机方法大全
  14. Fcitx 在 LumaQQ中的设置
  15. 使用VUE前端开发Lodop打印程序,实现网页打印模块
  16. android data/app下的文件被误删,系统恢复,怎样恢复被误删除的文件
  17. 正方形面积圆形面积Java
  18. android屏幕重力感应器,android屏幕重力感应如何实现,很质量的一个问题
  19. 文本蕴涵模型测试过程
  20. re匹配截至到第一个中文_Python正则表达式:re模块常用方法详解

热门文章

  1. 阿里、网易、华为......滨江哪家公司奋战到最晚?论加班,你是斗不过他们的
  2. word2019文档中输入空格变成省略号圆点正方形空白框去除方法
  3. Be Agile VS Do Agile 之 1
  4. 币币交易和法币交易有什么不同之处!!exu
  5. 【动物篇】蚂蚁和大象
  6. iOS7免费设计资源汇总
  7. 关于spring与EHcache的集成
  8. 关于CSP-J/S 个人信息注册及认证语言选择的说明!
  9. svn服务器目录变更后本地有新代码需要提交到新地址方法
  10. 安卓与IOS的H5差异性