返回顶部
首页 > 资讯 > 数据库 >PostgreSQL中的GIN索引有什么作用
  • 384
分享到

PostgreSQL中的GIN索引有什么作用

2024-04-02 19:04:59 384人浏览 八月长安
摘要

本篇内容主要讲解“postgresql中的GIN索引有什么作用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Postgresql中的GIN索引有什么作用”吧!G

本篇内容主要讲解“postgresql中的GIN索引有什么作用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Postgresql中的GIN索引有什么作用”吧!

GIN索引的主要用处是加快全文检索full-text search的速度.

全文检索
全文检索full-text search的目的是从文档集中找到匹配检索条件的文档(document).在搜索引擎中,如果有很多匹配的文档,那么需要找到最匹配的那些,但在数据库查询中,找到满足条件的即可.

在PG中,出于搜索的目的,文档会被转换为特定的类型tsvector,包含词素(lexemes)和它们在文档中的位置.词素Lexemes是那些转换适合查询的单词形式(即分词).比如:

testdb=# select to_tsvector('There was a crooked man, and he walked a crooked mile');
               to_tsvector               
-----------------------------------------
 'crook':4,10 'man':5 'mile':11 'walk':8
(1 row)

从本例可以看到,分词后,出现了crook/man/mile和walk,其位置分别是4,10/5/11/8.同时,也可以看到比如there等词被忽略了,因为这些词是stop Words(从搜索引擎的角度来看,这些词太过普通,不需要记录),当然这是可以配置的.

PG全文检索中的查询通过tsquery来表示,查询条件包含1个或多个使用and(\&)/or(|)/not(!)等操作符连接的词素.同样的,使用括号来阐明操作的优先级.

testdb=# select to_tsquery('man & (walking | running)');
         to_tsquery         
----------------------------
 'man' & ( 'walk' | 'run' )
(1 row)

操作符 @@ 用于全文检索

testdb=# select to_tsvector('There was a crooked man, and he walked a crooked mile') @@ to_tsquery('man & (walking | running)');
 ?column? 
----------
 t
(1 row)
select to_tsvector('There was a crooked man, and he walked a crooked mile') @@ to_tsquery('man & (Going | running)');
 ?column? 
----------
 f
(1 row)

GIN简介
GIN是Generalized Inverted Index通用倒排索引的简称,如熟悉搜索引擎,这个概念不难理解.它所操作的数据类型的值由元素组成而不是原子的.这样的数据类型成为复合数据类型.索引的是数据值中的元素.
举个例子,比如书末尾的索引,它为每个术语提供了一个包含该术语出现位置所对应的页面列表。访问方法(AM)需要确保索引元素的快速访问,因此这些元素存储在类似Btree中,引用包含复合值(内含元素)数据行的有序集合链接到每个元素上.有序对于数据检索并不重要(如TIDs的排序),但对于索引的内部结构很重要.
元素不会从GIN索引中删除,可能有人会认为包含元素的值可以消失/新增/变化,但组成这些元素的元素集大多是稳定的.这样的处理方式大大简化了多进程使用索引的算法.

如果TIDs不大,那么可以跟元素存储在同一个page中(称为posting list),但如果链表很大,会采用Btree这种更有效的数据结构,会存储在分开的数据页中(称为posting tree).
因此,GIN索引包含含有元素的Btree,TIDs Btree或者普通链表会链接到该Btree的叶子行上.

与前面讨论的GIST和SP-GiST索引一样,GIN为应用程序开发人员提供了接口,以支持复合数据类型上的各种操作。

举个例子,下面是表ts,为ts创建GIN索引:

testdb=# drop table if exists ts;
psql: NOTICE:  table "ts" does not exist, skipping
DROP TABLE
testdb=# create table ts(doc text, doc_tsv tsvector);
CREATE TABLE
testdb=# truncate table ts;
 slitter.'), 
  ('I am a sheet slitter.'),
  ('I slit sheets.'),
  ('I am the sleekest sheet slitter that ever slit sheets.'),
  ('She slits the sheet she sits on.');
update ts set doc_tsv = to_tsvector(doc);
create index on ts using gin(doc_tsv);
TRUNCATE TABLE
testdb=# insert into ts(doc) values
testdb-#   ('Can a sheet slitter slit sheets?'), 
testdb-#   ('How many sheets could a sheet slitter slit?'),
testdb-#   ('I slit a sheet, a sheet I slit.'),
testdb-#   ('Upon a slitted sheet I sit.'), 
testdb-#   ('Whoever slit the sheets is a good sheet slitter.'), 
testdb-#   ('I am a sheet slitter.'),
testdb-#   ('I slit sheets.'),
testdb-#   ('I am the sleekest sheet slitter that ever slit sheets.'),
testdb-#   ('She slits the sheet she sits on.');
INSERT 0 9
testdb=# 
testdb=# update ts set doc_tsv = to_tsvector(doc);
UPDATE 9
testdb=# 
testdb=# create index on ts using gin(doc_tsv);
CREATE INDEX

在这里,使用黑底(page编号 + page内偏移)而不是箭头来表示对TIDs的引用.
与常规的Btree不同,因为遍历只有一种方法,GIN索引由单向链表连接,而不是双向链表.

testdb=#  select ctid, left(doc,20), doc_tsv from ts;
  ctid  |         left         |                         doc_tsv                         
--------+----------------------+---------------------------------------------------------
 (0,10) | Can a sheet slitter  | 'sheet':3,6 'slit':5 'slitter':4
 (0,11) | How many sheets coul | 'could':4 'mani':2 'sheet':3,6 'slit':8 'slitter':7
 (0,12) | I slit a sheet, a sh | 'sheet':4,6 'slit':2,8
 (0,13) | Upon a slitted sheet | 'sheet':4 'sit':6 'slit':3 'upon':1
 (0,14) | Whoever slit the she | 'good':7 'sheet':4,8 'slit':2 'slitter':9 'whoever':1
 (0,15) | I am a sheet slitter | 'sheet':4 'slitter':5
 (0,16) | I slit sheets.       | 'sheet':3 'slit':2
 (0,17) | I am the sleekest sh | 'ever':8 'sheet':5,10 'sleekest':4 'slit':9 'slitter':6
 (0,18) | She slits the sheet  | 'sheet':4 'sit':6 'slit':2
(9 rows)

在这个例子中,sheet/slit/slitter使用Btree存储而其他元素则使用简单的链表.

如果我们希望知道元素的个数,如何获取?

testdb=# select (unnest(doc_tsv)).lexeme, count(*) from ts
testdb-# group by 1 order by 2 desc;
  lexeme  | count 
----------+-------
 sheet    |     9
 slit     |     8
 slitter  |     5
 sit      |     2
 upon     |     1
 mani     |     1
 whoever  |     1
 sleekest |     1
 good     |     1
 could    |     1
 ever     |     1
(11 rows)

下面举例说明如何通过GIN索引进行扫描:

testdb=# explain(costs off)
testdb-# select doc from ts where doc_tsv @@ to_tsquery('many & slitter');
                        QUERY PLAN                         
-----------------------------------------------------------
 Seq Scan on ts
   Filter: (doc_tsv @@ to_tsquery('many & slitter'::text))
(2 rows)
testdb=# set enable_seqscan=off;
SET
testdb=# explain(costs off)
select doc from ts where doc_tsv @@ to_tsquery('many & slitter');
                             QUERY PLAN                              
---------------------------------------------------------------------
 Bitmap Heap Scan on ts
   Recheck Cond: (doc_tsv @@ to_tsquery('many & slitter'::text))
   ->  Bitmap Index Scan on ts_doc_tsv_idx
         Index Cond: (doc_tsv @@ to_tsquery('many & slitter'::text))
(4 rows)

执行此查询首先需要提取单个词素(lexeme,亦即检索键):mani/slitter.PG中有专门的api函数来完成,该函数考虑了由op class确定的数据类型和使用场景.

testdb=# select amop.amopopr::regoperator, amop.amopstrategy
testdb-# from pg_opclass opc, pg_opfamily opf, pg_am am, pg_amop amop
testdb-# where opc.opcname = 'tsvector_ops'
testdb-# and opf.oid = opc.opcfamily
testdb-# and am.oid = opf.opfmethod
testdb-# and amop.amopfamily = opc.opcfamily
testdb-# and am.amname = 'gin'
testdb-# and amop.amoplefttype = opc.opcintype;
        amopopr        | amopstrategy 
-----------------------+--------------
 @@(tsvector,tsquery)  |            1
 @@@(tsvector,tsquery) |            2
(2 rows)

回到本例中,在词素Btree中,下一步会同时检索键并进入TIDs链表中,得到:
mani — (0,2)
slitter — (0,1), (0,2), (1,2), (1,3), (2,2)

对于每一个找到的TID,调用consistency function API,由此函数确定找到的行是否匹配检索键.因为查询为AND,因此只返回(0,2).

testdb=# select doc from ts where doc_tsv @@ to_tsquery('many & slitter');
                     doc                     
---------------------------------------------
 How many sheets could a sheet slitter slit?
(1 row)

Slow Update
对GIN index的列进行DML(主要是insert & update)是相当慢的,每一个文档通常包含许多需要索引的词素.因此,虽然只添加或更新一个文档,但也需要更新大量索引树.换句话说,如果多个文档同时更新,这些文档中的词素可能是一样的,因此总的消耗可能比逐个更新文档要小.
PG提供了fastupdate选项,用打开此参数后,更新将在一个单独的无序链表中处理,当这个链表超过阈值(参数:gin_pending_list_limit或索引同名存储参数)时才会对索引进行更新.这种技术也有负面影响,一是降低了查询效率(需额外扫描该链表),二是某个更新恰好碰上索引更新,那么该次更新会相对很久.

Limiting the query result
GIN AM的其中一个特性时通常会返回bitmap而不是逐个返回TID,因此执行计划都是bitmap scan.
这样的特性胡导致LIMIT子句不会太有效:

testdb=# explain verbose   
select doc from ts where doc_tsv @@ to_tsquery('many & slitter');
                                  QUERY PLAN                                  
------------------------------------------------------------------------------
 Bitmap Heap Scan on public.ts  (cost=12.25..16.51 rows=1 width=32)
   Output: doc
   Recheck Cond: (ts.doc_tsv @@ to_tsquery('many & slitter'::text))
   ->  Bitmap Index Scan on ts_doc_tsv_idx  (cost=0.00..12.25 rows=1 width=0)
         Index Cond: (ts.doc_tsv @@ to_tsquery('many & slitter'::text))
(5 rows)
testdb=# explain verbose
select doc from ts where doc_tsv @@ to_tsquery('many & slitter') limit 1;
                                     QUERY PLAN                                     
------------------------------------------------------------------------------------
 Limit  (cost=12.25..16.51 rows=1 width=32)
   Output: doc
   ->  Bitmap Heap Scan on public.ts  (cost=12.25..16.51 rows=1 width=32)
         Output: doc
         Recheck Cond: (ts.doc_tsv @@ to_tsquery('many & slitter'::text))
         ->  Bitmap Index Scan on ts_doc_tsv_idx  (cost=0.00..12.25 rows=1 width=0)
               Index Cond: (ts.doc_tsv @@ to_tsquery('many & slitter'::text))
(7 rows)

这是因为Bitmap Heap Scan的启动成本与Bitmap Index Scan不会差太多.

基于这样的情况,PG提供了gin_fuzzy_search_limit参数控制返回的结果行数(默认为0,即全部返回).

testdb=# show gin_fuzzy_search_limit ;
 gin_fuzzy_search_limit 
------------------------
 0
(1 row)

到此,相信大家对“PostgreSQL中的GIN索引有什么作用”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

您可能感兴趣的文档:

--结束END--

本文标题: PostgreSQL中的GIN索引有什么作用

本文链接: https://lsjlt.com/news/63812.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • PostgreSQL中的GIN索引有什么作用
    本篇内容主要讲解“PostgreSQL中的GIN索引有什么作用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PostgreSQL中的GIN索引有什么作用”吧!G...
    99+
    2024-04-02
  • PostgreSQL中的Btree索引有什么作用
    本篇内容主要讲解“PostgreSQL中的Btree索引有什么作用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PostgreSQL中的Btree索引有什么作用...
    99+
    2024-04-02
  • PostgreSQL中的Declarations有什么作用
    本篇内容主要讲解“PostgreSQL中的Declarations有什么作用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PostgreSQL中的Declara...
    99+
    2024-04-02
  • PostgreSQL中的​Rules有什么作用
    本篇内容介绍了“PostgreSQL中的Rules有什么作用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!...
    99+
    2024-04-02
  • 怎么使用PostgreSQL中的Bloom索引
    这篇文章主要讲解了“怎么使用PostgreSQL中的Bloom索引”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么使用PostgreSQL中的Bloom索...
    99+
    2024-04-02
  • MySQL的前缀索引有什么作用?
    MySQL的前缀索引有什么作用?(1500字) 导言 在MySQL数据库中,索引是一种提高数据检索效率的重要技术手段。前缀索引是一种特殊类型的索引,它可以在某些情况下有效地减小索引的大...
    99+
    2024-03-14
    mysql 作用 前缀索引 内存占用
  • MySQL中的索引有什么用
    这篇文章主要介绍了MySQL中的索引有什么用,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。索引1、索引的优势(1)提高查询效率(降低IO使用率)(2)降低CPU使用率比如查询...
    99+
    2023-06-27
  • PostgreSQL中ReceiveXlogStream有什么作用
    这篇文章主要介绍“PostgreSQL中ReceiveXlogStream有什么作用”,在日常操作中,相信很多人在PostgreSQL中ReceiveXlogStream有什么作用问题上存在疑惑,小编查阅了...
    99+
    2024-04-02
  • PostgreSQL中RecordAndGetPageWithFreeSpace有什么作用
    本篇内容介绍了“PostgreSQL中RecordAndGetPageWithFreeSpace有什么作用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处...
    99+
    2024-04-02
  • PostgreSQL中pgbench有什么作用
    本篇内容主要讲解“PostgreSQL中pgbench有什么作用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PostgreSQL中pgbench有什么作用”吧...
    99+
    2024-04-02
  • PostgreSQL中pgmetrics有什么作用
    本篇内容主要讲解“PostgreSQL中pgmetrics有什么作用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PostgreSQL中pgmetrics有什么...
    99+
    2024-04-02
  • 怎么使用PostgreSQL中Hash索引
    本篇内容介绍了“怎么使用PostgreSQL中Hash索引”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!逻...
    99+
    2024-04-02
  • Mysql索引下推有什么作用
    这篇文章主要讲解了“Mysql索引下推有什么作用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Mysql索引下推有什么作用”吧!导读索引下推(index c...
    99+
    2024-04-02
  • mysql中索引有什么用
    今天就跟大家聊聊有关mysql中索引有什么用,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。1、概念MySQL定义是指数(Index)是帮助MySQL有效地获取数据的数据结构。MySQ...
    99+
    2023-06-15
  • PostgreSQL中的User subroutines有什么作用
    本篇内容介绍了“PostgreSQL中的User subroutines有什么作用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔...
    99+
    2024-04-02
  • 索引的作用是什么
    索引的作用:可以利用它加速对数据的检索。保证数据记录的唯一性。可以加速表和表之间的连接。利用索引可以减少排序和分组的时间。利用索引可以加快条件的判断速度。...
    99+
    2024-04-02
  • postgresql有什么作用
    小编给大家分享一下postgresql有什么作用,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!PostgreSQL 是一个免费的...
    99+
    2024-04-02
  • mysql中BTree索引的作用是什么
    本篇文章给大家分享的是有关mysql中BTree索引的作用是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。1、概念BTree又叫多路平衡查找树。所有结点存储一个关键字。非叶...
    99+
    2023-06-15
  • pandas中index索引的作用是什么
    这篇文章给大家介绍pandas中index索引的作用是什么,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。一、index索引特点更方便的数据查询,使用index查询的时候可以获得性能提升;自动的数据对齐功能;更多更强大的...
    99+
    2023-06-14
  • Numpy在索引中的作用是什么?
    Numpy是Python中最常用的科学计算库之一,它提供了一个强大的多维数组对象,以及各种用于操作数组的函数和方法。在Numpy中,索引是非常重要的一个概念,它可以帮助我们快速地访问和操作数组中的元素。本文将介绍Numpy中索引的作用,以及...
    99+
    2023-06-04
    numpy 自然语言处理 索引
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作