Greenplum数据库索引解析

以下是对greenplum数据库使用总结。

  • 创建索引

  CREATE INDEX i_test_tb_state_az ON test_tb(name_en) WHERE name_en = 'AZ';

  当一个表很大的时候,为每一行都建索引是很耗存储空间的。如果常用的数据只有一小部分的话,完全可以只为这部分数据建立索引,省时省力省空间。

  省时:当做Insert和Update操作的时候,额外开销更小。
  省力:热数据索引扫描更快。
  省空间:索引再也不用耗费大量磁盘了。

  • 索引使用建议:
  1. 如果是从超大结果集合中返回非常小的结果集(不超过5%),建议使用BTREE索引(非典型数据仓库操作)
  2. 表记录的存储顺序最好与索引一致,可以进一步减少IO(好的index cluster)
  3. where条件中的列用or的方式进行join,可以考虑使用索引
  4. 键值大量重复时,比较适合使用bitmap索引
  • 索引使用规范

1.不要给经常变更的列建索引。全表扫描性能不好时才需要创建索引。

2.不要建重复的索引并给索引命名。

3.低基数的列用bitmap索引。单列的查询使用B-Tree索引。

4.加载数据的时候先drop掉索引,加载之后再重新创建索引。

5.扫描一个大表的子集时,使用部分索引。

6.重创建索引执行执行Analyze。Explain一下你常用的查询,如果seq_scan的cost很高,可以考虑建立索引。但是相应的,如果一个索引的idx scan很少被用到,就要考虑这个索引是不是还应该继续存在了。毕竟,维护一个索引是耗时耗空间的事情。

7.在此之外,还可以从以下几点考虑:数据类型、索引建立的时间、索引存储空间、数据更新时索引带来的额外开销、访问速度等。

  • 常用索引介绍

  传统索引方式(B-Tree)

    说到传统,B-Tree索引当仁不让,它也是postgres里的默认索引方式。B-Tree的中文名字是二叉平衡树,每个叶子结点的深度都是一样的,特点是允许在O(logn)的时间内对所存储的内容进行搜索、顺序访问、插入及删除。
  B-Tree索引作用和特点

    B-Tree索引对于唯一值的索引来说是相当之理想的(比如id序号这类数据),它存储的是一对对的键值和指针,指针指向被索引数据所在的heap上的位置。这里说下什么是heap。Heap(或者叫heap文件,用来区分同名不同义的数据结构heap)存储着postgres表里的所有数据(外部表除外)。heap里边的数据是无序的,这让数据库在向里面添加数据的时候不必考虑排序的问题。目前postgres支持的索引中,只有B-Tree索引能够提供有序的查询结果(也就是支持Order by和Limit),支持高并发场景(并行scan),支持merge join和包含index scan的nested loop操作。

  BRIN (Block-Range Index)

    名字里有个range,顾名思义,这种索引存储的是heap表内每个block中数据的最大值和最小值。

  BRIN索引作用和特点

    首先,如果一整个block里的数据都非常大或者非常小,不在我们查询的条件范围内,就可以将整个block排除出扫描范围。这种索引对那些分布是有序的数据非常有用,比如insert-only table的id或timestamp列。其次,因为只存储最大值和最小值,BRIN带来的空间消耗极小。另外,更新数据的时候,索引带来的额外操作只有比较操作,也是相当高效的。BRIN对于含有多个列的索引是比较合适的选择。但是,因为索引里存储的信息非常少,查找数据的时候消耗的时间也会很长,当查询的数据范围和一个block的范围值有重叠时,就需要对这个block进行scan,如果有重叠的block很多,其实跟全表扫描的差别也不大了。

  GIN (Generalized Inverted Index)索引

    尤其适用于有很多key或value的数据的索引,比如说文档、JSON、整型数组等等。尤其适用于重复数据很多的场景,这点和B-Tree正好相反。支持一条索引里存在多个key。而B-Tree每条索引里只能有一个key。比如新插入一条数据“foo bar”,GIN会拆分出两个key:“foo” 和 “bar”。GIN索引内部数据结构整体上类似于B-Tree。不同的是,叶子结点上存储的不是一个TID,而是很多TID的集合,这是GIN为了存储重复数据做的优化。GIN的叶子结点的数据有三种可能:

    当只有一个TID的时候,和B-Tree一样。当有很多TID的时候,那么存储的是一个列表(posting list)。当有非常非常多的TID的时候,叶子结点存储的是一个指针,这个指针指向另一棵树(Posting Tree)的根结点。而Posting Tree里面存储了所有符合这一个entry的TIDs(以page为存储单元)。

  GIN索引的Fast Updates特性:
    GIN额外维护着一个列表,当有新的数据进入索引,不会直接进入索引树,而是会先暂存在这个列表里。当然,每个对索引的搜索也都会额外的对这个列表进行扫描。当做vacuum操作的时候,会把这个列表里的数据插入到索引树上。不过,如果这个列表已经太大了,postgres不会傻傻等待用户进行vacuum,会果断地将它里面的内容插入GIN索引树。但有意思的是,虽然它叫Fast Updates,但这个特性会让搜索变慢,因为每次搜索都要增加一次额外的列表扫描操作,所以很多用户会把这个特性关掉。GIN索引适用于有大量重复关键字的全文索引,但是,当一个关键字出现次数太多时,返回结果也会很大,太大的结果集对用户是没有实际意义的,而且读取并排序这么多的数据会耗费很长时间。GIN提供了一个配置项gin_fuzzy_search_limit来控制这种情况下返回结果集的上限。如果这个值非0,那么查询只会返回不超过设置值的一个子结果集,而且是随机的。根据经验,这个值设定为5000-20000比较好。

  GIST (Generalized Search Tree)索引

    GIST的数据结构仍然是树,但不再是B-Tree了。支持地理坐标、range类型(比如ip范围)、hstore(key/value对)、整型数组、pg_trgm。如果是B-Tree,可以按照range的最大值或最小值进行排序,但仍然避免不了每次查询都要做扫描。GIST的做法,是将范围差不多的数据聚集在一起,形成一个个的“clusters”,每个cluster的最大值和最小值都在根结点上记录,这样就可以按照每个cluster的整体范围,排除掉那些根本不可能有重叠的cluster,大大降低了扫描成本。

  GIST的用途
    GIS (geographic information system)、寻找bounding box的顶点、找到最近的n个邻居、全文检索、整型数组,一句话总结:GIST适合上层结点的范围能“包含”下层结点的类型。

  SP-GIST (Space-Partitioned Generalized Search Tree)索引

    虽然和GIST名字相似,但却是完全不同的索引类型,不是平衡树,各个叶子节点的深度可以不同。GIST各个cluster之间是可以有范围重叠的,但是SP-GIST不允许重叠。这是一个网址数据索引的例子,父节点是各个子节点的共有前缀,一个完整的键值在SP-GIST的树上只存一次,每一部分分别存储在从根结点到该键值叶子节点的路径上。另外一个常见的使用场景是索引坐标点:将空间分割成不重叠的块,每个子节点再将父节点的空间细分。但是如果是空间里的形状,就无法使用SP-GIST来索引了,因为形状可能有重叠。

  • 常见索引特点

  建立B树索引:B树索引是现网数据库中最常见的索引类型之一,它适用范围比较广

    1.适合于拥有重复值较少的字段。数据重复值越少,查询数据选择性越高,使用索引查询数据的效率越高,反之则越低。

    2.适用于对字段所在数据有少量修改的场合,例如字段有较少量的插入、修改、删除等情况,更新索引字段键值的代价适中。

    3.适用于数据变化相对频繁的OLTP系统。

    4.需要占用较高的存储空间。

  建立位图索引:位图索引是数据分析系统中常见的索引类型之一

    1.适合于拥有较高重复值的字段,数据重复值对索引查询的效率影响较少。

    2.适用于对字段所有数据只读或者极少修改的场合,更新索引字段键值将付出巨大的代价。

    3.适用于数据变化很少的DSS数据分析系统。

    4.需要较小的存储空间。

  建立哈希索引:Hash 索引只能处理简单的等于比较,当一个索引了的列涉及到使用 = 操作符进行比较的时候,查询规划器会考虑使用 Hash 索引。

    1.Hash索引的性能不比B-tree索引强。

    2.Hash索引的创建时间会很长。

    3.如果发生了数据库崩溃,可能要重建Hash索引。

    4.基于以上原因不推荐使用Hash索引。

  建立基于函数索引:B-tree索引的一种,创建基于函数的索引,适用于以下两种情况:

    1.基于对索引键值进行各种函数运算,例如对字符串字段进行大写转换upper()运算。

    2,.基于对一个或者多个字段进行各种运算,例如对两个数值字段进行相加运算colA+colB等。

    3.创建基于函数的索引,可以提高在查询条件中对索引使用基于特定函数的效率。因此,一个频繁执行并且需要对特定字段进行特定函数转换的查询语句。但是建立基于函数的索引,无法对使用字段本身或者对字段进行其它函数操作的查询语句起到优化的效果。

  建立部分索引:部分索引是建立在一个表的子集上的索引。

    部分索引的主要动机是为了避免对普通数值(大量重复的数值)建立索引。因为在普通数值上的查询就算使用索引也没什么好处,那么还不如从索引中剔除这些大量重复的行。这样可以减小索引尺寸,提高那些真正使用索引的查询的速度。同时它也能提高更新操作的速度,因为不是所有情况都需要更新索引。

参考资料:

  中文文档:https://ask.greenplum.cn/topic/245/50723073
  官方文档:http://docs.greenplum.org/6-8/common/gpdb-features.html

原文地址:https://www.cnblogs.com/zengming/p/13138058.html