GiST索引是PostgreSQL中很神奇的一个东西,通过它有时可以轻松玩转多维数据。但是,在不恰当的使用场景下,它的性能表现也可能令人困惑。
要深入研究GiST的话可参考下面的资料:
1)Marcel Kornacker 的论文,Access Methods for Next-Generation Database Systems:http://citeseer.nj.nec.com/448594.html,或PPT版http://www.doc88.com/p-9943363705540.html
2)Gist维护网站:http://www.sai.msu.su/~megera/postgres/gist/
1.概述
1.1 GiST为何物
GiST 的意思是通用的搜索树(Generalized Search Tree)。 它是一种平衡的,树状结构的访问方法,在系统中起一个基础模版 的作用,可以使用它实现任意索引模式。B+-trees,R-trees 和许多其它的索引模式都可以用 GiST实现。要深入研究GiST的话可参考下面的资料:
1)Marcel Kornacker 的论文,Access Methods for Next-Generation Database Systems:http://citeseer.nj.nec.com/448594.html,或PPT版http://www.doc88.com/p-9943363705540.html
2)Gist维护网站:http://www.sai.msu.su/~megera/postgres/gist/
1.2 如何实现一个GiST索引
GiST自身只是一个框架,针对不同的数据类型和算法逻辑需要额外实现特定的数据语义。由于GiST屏蔽了数据库的内部工作机制,比如锁的机制和预写日志。所以实现新的GiST索引实例(或称作索引操作符类)的工作相对比较轻松,基于GiST架构的索引操作符类只需提供下面7个方法的实现
(第8个方法是可选的):
consistent
给出一个在树的数据页上的谓词 p,和一个用户查询 q, 如果对于一个给定的数据项,p 和 q 都很明确地不能为真,那么这个方法将返回假。
union
这个方法合并树中的信息。给出一个条目的集合,这个函数生成一个新的谓词, 这个谓词对所有这些条目都为真。
compress
将数据项转换成一个适合于在一个索引页里面物理存储的格式。
decompress
compress 方法的反方法。把一个数据项的索引表现形式 转换成可以由数据库操作的格式。
penalty
返回一个表示将新条目插入树中特定分支需要的"开销"的数值。 项将会按照树中最小 penalty 的路径插下去。
picksplit
如果需要分裂一个页面的时候,这个函数决定页面中哪些条目保存呆旧页面里, 而哪些移动到新页面里。
same
如果两个条目相同,返回真,否则返回假。
详细参考PG手册:http://58.58.27.50:8079/doc/html/9.3.1_zh/gist.html
B-tree
适用于可比较大小的一维数据类型。由btree_gist模块提供,针对一些数据类型的B-tree等价功能。比如索引操作符类gist_int4_ops。不知道这个 btree_gist 模块存在的价值是否仅仅作为如何实现gist索引操作符类的一个示例,因为对一维数据直接用原生的btree索引就可以了。
R-Tree
适用于在每个单维度上可进行大小比较的 多维数据类型。几种几何数据类型的GiST实现就是用的R-Tree算法。比如point,box。另外还有范围类型等也是R-Tree的算法。关于R-Tree的原理,资料很多,就不多说了。
RD-tree
RD-tree可用于集合数据类型的索引,intarray模块提供了int4值的一维数组的RD-Tree索引实现
关于RD-tree的原理,看这张图就可以明白了。
参考:
http://wenku.baidu.com/link?url=thyllFOiO67gpI_19mY9bJ2LnU6KY2XeTV3OAqRHGlI_LvVgfoHyu59zXhFoycQFtBk8377y52fUeYjIruFUfYsf9yE0iDvhkUsDCA2n82S
签名文件索引(Signature File Index)
RD-Tree作为集合索引,在 索引 项目包含的元素很多时其key的大小会急剧膨胀。因此PostgreSQL中的一些GiST操作符类实现中,使用签名的方法对 索引 项目的key进行了压缩。看其实现方法,和 签名文件索引很像,不妨先叫它签名文件索引(也许应该叫另外的名字)。tsvector(以及tsquery),hstore,pg_trgm等很多重要的集合数据类型都是用的这个作为GiST索引算法。
以下是通用的 签名文件索引的简单介绍。
http://book.51cto.com/art/200906/128323.htm
--------------------------------------------- ---------------------------------------------
1.存储阶段
consistent
给出一个在树的数据页上的谓词 p,和一个用户查询 q, 如果对于一个给定的数据项,p 和 q 都很明确地不能为真,那么这个方法将返回假。
union
这个方法合并树中的信息。给出一个条目的集合,这个函数生成一个新的谓词, 这个谓词对所有这些条目都为真。
compress
将数据项转换成一个适合于在一个索引页里面物理存储的格式。
decompress
compress 方法的反方法。把一个数据项的索引表现形式 转换成可以由数据库操作的格式。
penalty
返回一个表示将新条目插入树中特定分支需要的"开销"的数值。 项将会按照树中最小 penalty 的路径插下去。
picksplit
如果需要分裂一个页面的时候,这个函数决定页面中哪些条目保存呆旧页面里, 而哪些移动到新页面里。
same
如果两个条目相同,返回真,否则返回假。
详细参考PG手册:http://58.58.27.50:8079/doc/html/9.3.1_zh/gist.html
1.3 GiST索引的效率
谈到GiST索引的效率,关键还是看索引操作符类使用的索引算法。理解了索引算法也就大致可以了解某个数据类型在某个应用场景下是否适合创建GiST索引。这不像Gin索引,Gin索引的 基本算法固定 是倒排索引。目前PostgreSQL内置的GiST索引操作符类,主要使用了下面这些索引算法。B-tree
适用于可比较大小的一维数据类型。由btree_gist模块提供,针对一些数据类型的B-tree等价功能。比如索引操作符类gist_int4_ops。不知道这个 btree_gist 模块存在的价值是否仅仅作为如何实现gist索引操作符类的一个示例,因为对一维数据直接用原生的btree索引就可以了。
R-Tree
适用于在每个单维度上可进行大小比较的 多维数据类型。几种几何数据类型的GiST实现就是用的R-Tree算法。比如point,box。另外还有范围类型等也是R-Tree的算法。关于R-Tree的原理,资料很多,就不多说了。
![](https://i-blog.csdnimg.cn/blog_migrate/24ed3ee6d2035331ff3d26a4c968318f.jpeg)
RD-tree
RD-tree可用于集合数据类型的索引,intarray模块提供了int4值的一维数组的RD-Tree索引实现
关于RD-tree的原理,看这张图就可以明白了。
![](https://i-blog.csdnimg.cn/blog_migrate/589023d0298085e015cef83c1134ef3a.png)
参考:
http://wenku.baidu.com/link?url=thyllFOiO67gpI_19mY9bJ2LnU6KY2XeTV3OAqRHGlI_LvVgfoHyu59zXhFoycQFtBk8377y52fUeYjIruFUfYsf9yE0iDvhkUsDCA2n82S
签名文件索引(Signature File Index)
RD-Tree作为集合索引,在 索引 项目包含的元素很多时其key的大小会急剧膨胀。因此PostgreSQL中的一些GiST操作符类实现中,使用签名的方法对 索引 项目的key进行了压缩。看其实现方法,和 签名文件索引很像,不妨先叫它签名文件索引(也许应该叫另外的名字)。tsvector(以及tsquery),hstore,pg_trgm等很多重要的集合数据类型都是用的这个作为GiST索引算法。
以下是通用的 签名文件索引的简单介绍。
http://book.51cto.com/art/200906/128323.htm
--------------------------------------------- ---------------------------------------------
1.存储阶段
对于每个关键字,分配一个固定大小的向量(k-bit),这个向量叫做签名(Signature);对于一个网页文件,经过词典切分后,形成由对应关键字序列构成的向量,即P=,对这些关键字的签名做OR运算,就形成了网页文件的签名。这个过程也被称为重叠编码(Superimposed Coding),然后把网页文件的签名结果依次存入一个个独立的文件中,形成对应的签名文件,这样形成的签名文件比原文件小很多。
例如:有一页网页分词后有这样一些关键字“文本”、“英语”、“单词”、“信件”,假设将这些关键字经某哈希表散列成固定位的数字向量(以6位为例),分别为hash(文本)=000110,hash(英语)= 110001,hash(单词)= 001101,hash(信件)=000111,这些数字向量即为关键字的签名,然后将这些签名做OR运算,得到网页文件的签名。
2.查询阶段
接受用户查询语句A,首先把用户查询串字符串切分成关键字序列,形成查询向量,即A=。然后把关键字映射成相应的向量签名,再与网页签名文件进行按位与运算,得到最后的匹配结果。
------------------------------------------------------------------------------------------