`
骑猪逛街666
  • 浏览: 142033 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

PostgreSQL 10 GIN索引 锁优化

 
阅读更多

阅读原文请点击

摘要: 标签 PostgreSQL , gin , 倒排索引 , 全文检索 , 性能优化 背景 PostgreSQL gin索引接口常被用于多值列的检索,例如全文检索类型、数组类型。 有兴趣了解更多索引接口的原理和使用场景,可以参考下文。

标签

PostgreSQL , gin , 倒排索引 , 全文检索 , 性能优化


背景

PostgreSQL gin索引接口常被用于多值列的检索,例如全文检索类型、数组类型。

有兴趣了解更多索引接口的原理和使用场景,可以参考下文。

《PostgreSQL 9种索引的原理和应用场景》

今天要说道一下PostgreSQL GIN索引的代码优化。

在说GIN代码优化前,我们先来看一个场景,以及在老版本下的性能表现。

例子

创建一张测试表,三个字段,其中一个全文检索字段,另一个PK,还有一个时间。

全文检索字段使用随机字符串生成,建立索引。

create table test(id int, info tsvector, crt_time timestamp);  
  
-- 生成随机字符串  
CREATE OR REPLACE FUNCTION public.gen_rand_str(integer)            
 RETURNS text            
 LANGUAGE sql            
 STRICT            
AS $function$            
  select string_agg(a[random()*6+1],'') from generate_series(1,$1), (select array['a','b','c','d','e','f',' ']) t(a);            
$function$;   
  
-- 插入100万条数据  
insert into test select generate_series(1,1000000), to_tsvector(gen_rand_str(512)), now();  
  
-- 创建索引  
create index idx_test_info on test using gin (info);  
create index idx_test_id on test (id);  

测试SQL

更新crt_time时间字段,但是不更新全文检索字段。

\set id random(1,1000000)  
update test set crt_time=now() where id=:id;  
  
或  
  
\setrandom id 1 1000000  
update test set crt_time=now() where id=:id;  

注意,虽然我们没有更新全文检索字段,但是依旧会导致GIN索引的变更,因为token->ctid,由于PG多版本的原因这里的ctid会变化,如果CTID变成了其他PAGE的行,那么索引也需要变化。

即使是更新后的记录在同一个PAGE(HOT更新),VACUUMM时将老的记录删掉也需要变更索引ENTRY。

总之这个为了突出业务上可能忽视的问题。以为不更新索引字段,索引就不需要变化。

PS:PG 10或将来会支持二级索引,就不会存在以上问题。那么用户只需要考虑索引字段VALUE被更新的情况。

PostgreSQL 9.4 版本压测

1、4并发

pgbench -M prepared -n -r -P 1 -f ./test.sql -c 4 -j 4 -T 1000  
progress: 1.0 s, 8622.0 tps, lat 0.091 ms stddev 0.041  
progress: 2.0 s, 9038.2 tps, lat 0.549 ms stddev 22.067  
progress: 3.0 s, 9910.5 tps, lat 0.466 ms stddev 18.571  
progress: 4.0 s, 11642.6 tps, lat 0.389 ms stddev 16.555  
progress: 5.0 s, 12109.2 tps, lat 0.386 ms stddev 16.879  
progress: 6.0 s, 9292.4 tps, lat 0.468 ms stddev 18.731  
progress: 7.0 s, 4511.1 tps, lat 0.077 ms stddev 0.023  
progress: 8.0 s, 15309.5 tps, lat 0.320 ms stddev 15.127  
progress: 9.0 s, 18481.9 tps, lat 0.274 ms stddev 13.459  
progress: 10.0 s, 22044.6 tps, lat 0.242 ms stddev 12.381  
progress: 11.0 s, 5432.4 tps, lat 0.789 ms stddev 26.151  
progress: 12.0 s, 22851.0 tps, lat 0.070 ms stddev 0.019  
progress: 13.0 s, 35955.7 tps, lat 0.175 ms stddev 10.177  

2、16并发

pgbench -M prepared -n -r -P 1 -f ./test.sql -c 16 -j 16 -T 1000  
progress: 1.0 s, 65915.6 tps, lat 0.104 ms stddev 0.075  
progress: 2.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 3.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 4.0 s, 20134.1 tps, lat 2.256 ms stddev 76.169  
progress: 5.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 6.0 s, 10403.8 tps, lat 3.658 ms stddev 90.374  
progress: 7.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 8.0 s, 9328.5 tps, lat 3.659 ms stddev 85.652  
progress: 9.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 10.0 s, 8348.0 tps, lat 3.787 ms stddev 84.213  
progress: 11.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 12.0 s, 7258.0 tps, lat 1.394 ms stddev 49.557  
progress: 13.0 s, 21.0 tps, lat 1231.018 ms stddev 1173.690  
progress: 14.0 s, 7237.3 tps, lat 1.228 ms stddev 48.168  
progress: 15.0 s, 13.0 tps, lat 1191.294 ms stddev 1108.031  
progress: 16.0 s, 9.0 tps, lat 1482.792 ms stddev 1657.674  
progress: 17.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 18.0 s, 6163.0 tps, lat 4.255 ms stddev 126.424  
progress: 19.0 s, 17.0 tps, lat 1785.435 ms stddev 1721.592  

3、64并发

pgbench -M prepared -n -r -P 1 -f ./test.sql -c 64 -j 64 -T 1000  
progress: 1.0 s, 2083.1 tps, lat 1.243 ms stddev 1.126  
progress: 2.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 3.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 4.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 5.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 6.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 7.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 8.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 9.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 10.0 s, 2030.1 tps, lat 300.032 ms stddev 1647.060  
progress: 11.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 12.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 13.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 14.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 15.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 16.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 17.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 18.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 19.0 s, 2064.0 tps, lat 289.639 ms stddev 1586.564  
progress: 20.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 21.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 22.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 23.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 24.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 25.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 26.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 27.0 s, 0.0 tps, lat -nan ms stddev -nan  
progress: 28.0 s, 0.0 tps, lat -nan ms stddev -nan  

我们发现,并发越高,性能抖动非常严重,但是数据库中并未发现waiting。

postgres=# select pid,query,waiting from pg_stat_activity ;  
  pid  |                      query                       | waiting   
-------+--------------------------------------------------+---------  
 39830 | update test set crt_time=now() where id=$1;      | f  
 39836 | update test set crt_time=now() where id=$1;      | f  
 39841 | update test set crt_time=now() where id=$1;      | f  
 39845 | update test set crt_time=now() where id=$1;      | f  
 39852 | update test set crt_time=now() where id=$1;      | f  
 39858 | update test set crt_time=now() where id=$1;      | f  
 39862 | update test set crt_time=now() where id=$1;      | f  
 39869 | update test set crt_time=now() where id=$1;      | f  
 39874 | update test set crt_time=now() where id=$1;      | f  

跟踪进程pstack,如下,出现了lock和sleep。

pstack 39926  

#0  0x00007f3836a21393 in __select_nocancel () from /lib64/libc.so.6  
#1  0x0000000000818d3a in pg_usleep ()  
#2  0x00000000006c2c66 in s_lock ()  
#3  0x00000000006a30ff in ReleaseBuffer ()  
#4  0x0000000000472320 in ginInsertValue ()  
#5  0x000000000046ad5a in ginEntryInsert ()  
#6  0x0000000000478552 in ginHeapTupleFastInsert ()   -- 插入pending list  
#7  0x000000000046b30a in gininsert ()  
#8  0x00000000007e13b7 in FunctionCall6Coll ()  
#9  0x000000000049fc5f in index_insert ()  
#10 0x00000000005c5975 in ExecInsertIndexTuples ()  
#11 0x00000000005d4db7 in ExecModifyTable ()  
#12 0x00000000005bb278 in ExecProcNode ()  
#13 0x00000000005b91fd in standard_ExecutorRun ()  
#14 0x00000000006d5816 in ProcessQuery ()  
#15 0x00000000006d5aef in PortalRunMulti ()  
#16 0x00000000006d5fda in PortalRun ()  
#17 0x00000000006d24d9 in exec_execute_message ()  
#18 0x00000000006d430c in PostgresMain ()  
#19 0x000000000066bcaf in PostmasterMain ()  
#20 0x00000000005f469c in main ()  

PG GIN索引有一个fastupdate的选项,实际上是因为一条记录涉及多个TOKEN,为了防止索引频繁更新,PG设计的一种快速DML方法。就是先将数据写入pending list,然后由vacuum, analyze或当list满时触发将pengding list合并到gin tree的动作。

代码分析

首先看一下pending list区域的大小由什么控制。

PostgreSQL 9.4

postgresql 9.4的pending list大小由work_mem参数控制。

https://www.postgresql.org/docs/9.4/static/gin-implementation.html#GIN-FAST-UPDATE

src/backend/access/gin/ginfast.c

/*  
 * Write the index tuples contained in *collector into the index's  
 * pending list.  
 *  
 * Function guarantees that all these tuples will be inserted consecutively,  
 * preserving order  
 */  
void  
ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)  
{  
  
......  
  
        /*  
         * Force pending list cleanup when it becomes too long. And,  
         * ginInsertCleanup could take significant amount of time, so we prefer to  
         * call it when it can do all the work in a single collection cycle. In  
         * non-vacuum mode, it shouldn't require maintenance_work_mem, so fire it  
         * while pending list is still small enough to fit into work_mem.  
         *  
         * ginInsertCleanup() should not be called inside our CRIT_SECTION.  
         */  
        if (metadata->nPendingPages * GIN_PAGE_FREESIZE > work_mem * 1024L)  
                needCleanup = true;  
  
        UnlockReleaseBuffer(metabuffer);  
  
        END_CRIT_SECTION();  
  
        if (needCleanup)  
                ginInsertCleanup(ginstate, false, NULL);  
}  

PostgreSQL 10

PostgreSQL 10的gin pending list大小由表级参数,或者全局参数gin_pending_list_limit控制。

https://www.postgresql.org/docs/10/static/gin-implementation.html

src/include/access/gin_private.h

#define GinGetPendingListCleanupSize(relation) \  
        ((relation)->rd_options && \  
         ((GinOptions *) (relation)->rd_options)->pendingListCleanupSize != -1 ? \  
         ((GinOptions *) (relation)->rd_options)->pendingListCleanupSize : \  
         gin_pending_list_limit)  
  
  
  
/*  
 * Write the index tuples contained in *collector into the index's  
 * pending list.  
 *  
 * Function guarantees that all these tuples will be inserted consecutively,  
 * preserving order  
 */  

阅读原文请点击

分享到:
评论

相关推荐

    postgresql索引类型区别

    PostgreSQL 索引类型区别 在 PostgreSQL 中,索引是提高查询效率的一种重要手段。不同的索引类型适用于不同的查询场景,了解它们的特点和区别对于...了解 PostgreSQL 中的索引类型可以帮助读者更好地优化数据库性能。

    PostgreSQL Like模糊查询优化方案

    PostgreSQL提供了丰富的全文检索功能,通过创建Gin或Gist索引,我们可以对特定字段进行全文索引。例如,可以创建一个tsvector类型的列,存储预处理的文本数据,然后使用to_tsquery函数进行查询。这样,即使在模糊...

    PGCon2014-GIN

    总的来说,该文档详细讲解了GIN索引在PostgreSQL中的工作原理以及如何在新版本中通过压缩posting列表和优化查询处理来提高查询效率和减少索引占用空间。此外,还讨论了GIN索引的扩展功能以及如何通过自定义扩展来...

    PostgreSQL 10 DBA菜谱源码

    2. **索引优化**:PostgreSQL支持多种类型的索引,包括B树、哈希、GiST、SP-GiST和GIN。源码可能涉及创建、管理和优化这些索引来提升查询性能,如使用EXPLAIN ANALYZE命令分析查询执行计划。 3. **视图与物化视图**...

    PostgreSQL 10 Administration Cookbook源码

    9. **高性能索引**:除了B-Tree索引,PostgreSQL还支持GiST、SP-GiST、GIN和BRIN等多种索引类型,选择合适的索引类型对于优化查询性能至关重要。 10. **扩展与插件**:PostgreSQL拥有丰富的扩展库,如哈希函数、...

    postgresql 10 high performance PDF、epub电子书和各章节中使用到的SQL语句文件

    《PostgreSQL 10 High Performance》是一本专为数据库管理员和开发者设计的指南,旨在帮助他们充分利用PostgreSQL 10的高性能特性。该书通过深入浅出的方式,讲解了如何优化查询性能、调整数据库配置、管理存储以及...

    PostgreSQL 9.0 High Performance

    - **索引类型**:PostgreSQL 支持多种索引类型,包括 B-tree、Hash、GiST、SP-GiST 和 GIN 等。了解不同类型的索引及其应用场景,能够显著提高查询效率。 - **索引选择**:合理选择索引类型对于提高查询速度至关重要...

    PostgreSQL 优化器入门简介

    B-Tree、GiST、SP-GiST、GIN和BRIN等索引类型各有优缺点,优化器会根据查询条件和索引特性进行选择。 2. **连接策略**:优化器可以使用嵌套循环、合并连接或哈希连接。对于多表连接,它会评估每种连接顺序的成本。 3...

    PostgreSQL 最佳性能优化实践授课PPT 386页

    理解B-Tree、GiST、SP-GiST、GIN和BRIN等不同类型的索引,以及何时使用它们,对于优化查询性能至关重要。 2. **查询优化器**:了解PostgreSQL的查询优化器如何选择执行计划,包括成本估算和并行查询的运用,可以...

    postgresql 10的中文离线手册

    PostgreSQL 10是PostgreSQL数据库系统的一个主要版本,它包含了丰富的功能更新和性能优化。这个中文离线手册是根据官方英文手册精心翻译而来,为中文用户提供了方便的学习和参考资源。手册通常会详细涵盖PostgreSQL ...

    PostGreSQL资料.zip

    2. **索引**:PostgreSQL支持多种类型的索引,包括B树、哈希、GiST(Generalized Search Tree)、SP-GiST(Spatial GiST)和GIN(Generalized Inverted Indexes)。合理地创建和使用索引可以显著提升查询速度。 3. ...

    postgresql杂志第0期中文版 最大化postgresql性能

    根据查询模式选择B-Tree、Gin、GiST或SP-GiST等不同类型的索引,可以显著提高数据检索速度。 - **统计信息**:定期更新数据库的统计信息,帮助优化器做出更准确的执行计划选择,避免全表扫描。 - **查询优化**:...

    Postgresql修炼之道 pdf

    3. 索引与性能优化:Postgresql支持多种索引类型,如B-tree、hash、GiST和Gin等,可以根据不同的查询需求来优化性能。了解如何合理使用索引是Postgresql优化中的关键技能。 4. 数据库管理:Postgresql数据库的安装...

    3-Ibrar--PostgreSQL Conf Beijing 2019 - Deep Dive to PostgreSQL Indexes.pdf

    在PostgreSQL中,实现了多种索引类型,包括B-tree、Hash、GiST和GIN等。每种索引类型适用于不同的场景和查询需求。例如,B-tree索引适合于数据有序存储,而Hash索引适合于快速精确查找。索引的具体类型和实现方式会...

    PostgreSQL教程(八):索引详解

    GiST和GIN复合索引则有不同特性,GiST对第一个字段的依赖性强,而GIN索引则不因字段子集的改变而影响效率。 6. **组合多个索引**: PostgreSQL允许在查询时组合使用多个索引,以处理单一索引无法满足的复杂查询。...

    PostgreSQL12.2中文手册.chm.7z

    4. **索引与查询优化**:索引是提升查询速度的关键,PostgreSQL支持B树、哈希、GiST、SP-GiST、GIN和BRIN等多种索引类型。手册将详细解析如何创建、管理和使用索引,以及如何通过EXPLAIN分析查询计划进行优化。 5. ...

    postgresql-8.3 下载

    GIN索引适合于快速查找数组或集合类型的列,而GiST则用于构建自定义的索引策略。 3. **分区表**: 虽然分区表在更早的版本中就已经存在,但在8.3中,PostgreSQL对分区表的支持更加成熟,允许用户根据日期、范围或...

    PostgreSQL9.3 DBA最佳实战培训PPT 580页

    - 索引优化:如何创建和使用B树、哈希、GiST和GIN等类型的索引以提高查询性能。 **4. 数据库安全与权限管理** - 用户与角色:创建和管理用户,分配权限,理解角色的概念。 - 权限控制:GRANT和REVOKE命令的使用,...

    postgresql-10.1

    PostgreSQL 10.1 对索引的存储结构进行了优化,尤其是B树索引,降低了磁盘空间的使用,并提升了插入和查询速度。同时,还引入了GIN(Generalized Inverted Indexes)和GiST(Generalized Search Tree)索引类型的...

    PostgreSQL 8.2.3 中文文档

    GIN 索引 52. 数据库物理存储 53. BKI 后端接口 54. 规划器如何使用统计信息 VIII. 附录 A. PostgreSQL 错误代码 B. 日期/时间支持 C. SQL 关键字 D. SQL 兼容性 F. CVS 仓库 G. 文档 H. 外部项目

Global site tag (gtag.js) - Google Analytics