• [技术干货] PostgreSQL插件之hll
    摘要HyperLogLog(hll)是一个用于计算集合中不重复的元素个数问题的算法,精确的计算需要与基数成比例的内存量,这对于非常大的数据集是不实际的。概率基数估算(如HyperLogLog算法)使用的内存要比这少得多,但代价是仅获得一个基数的近似值。背景在现实生活中,我们通常需要统计一个集合中不重复的元素个数。在数据库中通过使用如下的SQL语句进行精确统计:CREATE TABLE tbl(id INT, a INT); INSERT INTO tbl VALUES(1, 1), (2, 1), (3, 2), (4, 2), (5, 2), (6, 3); SELECT COUNT(DISTINCT a) FROM tbl;  count  -------      3 (1 row)为了计算 count-distinct 通常使用哈希或者排序的方式计算不重复元素个数。但是,如果数据量比较大,哈希或者排序消耗的内存较大。HyperLogLog 是处理这个问题的一个概率算法,但是其消耗资源较少。postgresql-hll插件引入了一个新的数据类型hll,它是一个HyperLogLog数据结构。下面对其使用进行详细介绍。支持版本PostgreSQL 12PostgreSQL 11PostgreSQL 10PostgreSQL 9.6PostgreSQL 9.5安装在华为云使用postgresql-hll,请参考:https://support.huaweicloud.com/usermanual-rds/rds_09_0043.html 进行安装和卸载。使用CREATE TABLE hll_tbl (     id      integer,     set     hll ); --- 插入空的HLL INSERT INTO hll_tbl(id, set) VALUES (1, hll_empty()); --- 增加一个被散列的整数值到HLL中 UPDATE hll_tbl SET set = hll_add(set, hll_hash_integer(12345)) WHERE id = 1; --- 增加一个被散列的字符串到HLL中 UPDATE hll_tbl SET set = hll_add(set, hll_hash_text('hello world')) WHERE id = 1; --- 计算HLL的基数 SELECT hll_cardinality(set) FROM hll_tbl WHERE id = 1;数据仓库示例我们假设有一个事实表,记录了用户对我的站点的访问、他们做了什么以及他们来自哪里。表中有上亿行数据,表扫描需要几分钟(或者至少需要很多秒)。CREATE TABLE facts (     date            date,     user_id         integer,     activity_type   smallint,     referrer        varchar(255) ); insert into facts select timestamp '2014-01-10 10:00:00' +        random() * (timestamp '2021-01-20 20:00:00' - timestamp '2014-01-10 10:00:00'),        generate_series(1, 10000000), 1, 'no use'; insert into facts select timestamp '2014-01-10 10:00:00' +        random() * (timestamp '2021-01-20 20:00:00' - timestamp '2014-01-10 10:00:00'),        generate_series(1, 10000000), 1, 'no use';如果想快速(毫秒级别)知道每天有多少独立用户访问了站点,可以建立一个聚合表:CREATE TABLE daily_uniques (     date            date UNIQUE,     users           hll ); INSERT INTO daily_uniques(date, users)     SELECT date, hll_add_agg(hll_hash_integer(user_id))     FROM facts     GROUP BY 1;我们首先对user_id进行散列,然后按天将这些散列后的值聚合为一个hll。现在我们可以计算每天的hll基数:SELECT date, hll_cardinality(users) FROM daily_uniques;如果想要得到这周独立的用户访问数呢?SELECT hll_cardinality(hll_union_agg(users))  FROM daily_uniques  WHERE date >= '2012-01-02'::date AND date <= '2012-01-08'::date;操作符插件中已经添加了一些操作符,使用hll变得不那么冗长。它们是最常用函数的简单别名。散列函数hll_hash_boolean(boolean)hll_hash_smallint(smallint)hll_hash_integer(integer)hll_hash_bigint(bigint)hll_hash_bytea(bytea)hll_hash_text(text)hll_hash_any(any)示例如下:SELECT hll_hash_boolean(TRUE); SELECT hll_hash_boolean(TRUE, 123/*hash seed*/); SELECT hll_hash_smallint(4::smallint); SELECT hll_hash_smallint(4::smallint, 123/*hash seed*/); SELECT hll_hash_integer(21474836); SELECT hll_hash_integer(21474836, 123/*hash seed*/); SELECT hll_hash_bigint(223372036854775808); SELECT hll_hash_bigint(223372036854775808, 123/*hash seed*/); SELECT hll_hash_bytea(E'\\xDEADBEEF'); SELECT hll_hash_bytea(E'\\xDEADBEEF', 123/*hash seed*/); SELECT hll_hash_text('foobar'); SELECT hll_hash_text('foobar', 123/*hash seed*/); SELECT hll_hash_any(123); SELECT hll_hash_any(123, 123/*hash seed*/);注意:hll_hash_any会动态地分派给适当的特定类型的函数,这使得它比它包装的特定类型的函数要慢。只有在不知道输入类型时才使用它。聚集函数如果要从表或结果集中创建一个hll,请使用hll_add_agg。这里的命名并不是特别有创意:它是一个聚合函数,将值添加到空的hll中。SELECT date, hll_add_agg(hll_hash_integer(user_id))     FROM facts     GROUP BY 1;上面的示例将为每个包含每天用户的日期提供一个hll。如果您想汇总已经存储到单个hll中的一个hll列表,请使用hll_union_agg。再次说明:它是一个聚合函数,将值合并到一个空的hll中。SELECT EXTRACT(MONTH FROM date), hll_cardinality(hll_union_agg(users))     FROM daily_uniques     GROUP BY 1;窗口是hll功能的另一个主要例子。执行滑动窗口惟一计数通常涉及一些generate_series技巧,对于已经计算过的滑动窗口则非常简单。SELECT date, #hll_union_agg(users) OVER seven_days     FROM daily_uniques     WINDOW seven_days AS (ORDER BY date ASC ROWS 6 PRECEDING);
  • [技术干货] 通过JDBC连接PostgreSQL数据库
    通过JDBC连接实例的方式有无需下载SSL证书连接和用户下载SSL证书连接两种,其中使用SSL证书连接通过了加密功能,具有更高的安全性。前提条件用户需要具备以下技能:熟悉计算机基础知识。了解java编程语言。了解JDBC基础知识。驱动获取及使用JDBC驱动下载地址:https://jdbc.postgresql.org/download.htmlJDBC接口使用指南请参考:https://jdbc.postgresql.org/documentation/head/index.html使用SSL证书连接说明:该方式属于SSL连接模式,需要下载SSL证书,通过证书校验并连接数据库。你可以在“实例管理”页面,单击实例名称进入“基本信息”页面,单击“数据库信息”模块“SSL”处的下载图标,下载根证书或**包。通过JDBC连接PostgreSQL数据库,代码中的JDBC链接格式如下:jdbc:postgresql://<instance_ip>:<instance_port>/<database_name>?sslmode=verify-full&sslrootcert=<ca.pem>参数说明:参数说明<instance_ip>如果通过弹性云服务器连接,“instance_ip”是主机IP,即“基本信息”页面该实例的“内网地址”。如果通过连接了公网的设备访问,“instance_ip”为该实例已绑定的“弹性公网IP”。<instance_port>端口,默认5432,当前端口,参考“基本信息”页面该实例的“数据库端口”。<database_name>数据库名,即需要连接的数据库名(默认的管理数据库是postgres)。sslmodessl连接模式,默认全认证模式。sslrootcertssl连接CA证书路径,该文件需放在执行该命令的路径下。连接PostgreSQL数据库的java代码,可参考以下示例import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; public class MyConnTest { final public static void main(String[] args) { Connection conn = null; // set sslmode here. // with ssl certificate and path. String url = "jdbc:postgresql://192.168.0.225:5432/my_db_test?sslmode=verify-full&sslrootcert=/home/Ruby/ca.pem"; try { Class.forName("org.postgresql.Driver"); conn = DriverManager.getConnection(url, "root", "password"); System.out.println("Database connected"); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("SELECT * FROM mytable WHERE columnfoo = 500"); while (rs.next()) { System.out.println(rs.getString(1)); } rs.close(); stmt.close(); conn.close(); } catch (Exception e) { e.printStackTrace(); System.out.println("Test failed"); } finally { // release resource .... } } }无证书连接说明:该方式属于SSL连接模式,但不对服务端进行证书校验,用户无需下载SSL证书。通过JDBC连接RDS PostgreSQL数据库实例,代码中的JDBC链接格式如下:jdbc:postgresql://<instance_ip>:<instance_port>/<database_name>?sslmode=disable连接PostgreSQL数据库的java代码,可参考以下示例:import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; public class MyConnTest { final public static void main(String[] args) { Connection conn = null; // set sslmode here. // no ssl certificate, so do not specify path. String url = "jdbc:postgresql://192.168.0.225:5432/my_db_test?sslmode=disable"; try { Class.forName("org.postgresql.Driver"); conn = DriverManager.getConnection(url, "root", "password"); System.out.println("Database connected"); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("SELECT * FROM mytable WHERE columnfoo = 500"); while (rs.next()) { System.out.println(rs.getString(1)); } rs.close(); stmt.close(); conn.close(); } catch (Exception e) { e.printStackTrace(); System.out.println("Test failed"); } finally { // release resource .... } } }
  • [技术干货] PostgreSQL13新特性介绍
    PostgreSQL 13.0版本已于2020-09-24发行,目前最新版为PostgreSQL 13.1。PostgreSQL 13版本中包含了令人欣喜的新特性和优化,其中典型的有:l  Btree索引优化(引入Deduplication技术)l  支持增量排序l  支持并行vacuum indexl  支持可信插件l  支持扩展统计信息l  支持hash aggregation使用磁盘存储 本文我们将选取几个PostgreSQL 13中的重点新特性进行介绍,让读者一睹为快。1.       Btree索引优化如果一张表的某些列值不是唯一的,那么将会存在很多重复值,一旦该列上建有索引的话,那么索引也会有很多重复的索引项。在PostgreSQL 13中引入了deduplicate功能,该功能将会定期的将重复的索引项合并,有效地减少了索引的存储空间。随着索引项的减少,重建索引、vacuum索引的速度都将获得提升,查询的效率也会得到提升。     下面我们分别在PostgreSQL 12 和 13 版本中创建唯一索引和包含大量重复项的索引,比较一下效果。测试脚本如下:CREATE TABLE test_tbl (id int4, str varchar(64), time timestamp without time zone); INSERT INTO test_tbl (id, str, time) SELECT round(100000000*random()), 'test_tbl_000' || num, '2020-12-31 24:00:00' FROM generate_series(1,6000000) num; CREATE UNIQUE INDEX idx_on_str ON test_tbl USING BTREE(str); CREATE INDEX idx_on_time ON test_tbl USING BTREE(time);    idx_on_str是唯一索引;idx_on_time是非唯一索引,存储的索引项都一样。    PostgreSQL 12 中 查看索引大小,如下:     在PostgreSQL 13 中查看索引大小:     根据以上信息可以看出,创建索引后,唯一索引在12版本13版本大小一致,都是232MB;但是非唯一索引的差别较大,13版本的非唯一索引大小约为12版本的1/3不到,减小了很多存储空间。2.       增量排序增量排序用在多列排序的场景下来加快排序速度。例如,下面的SQL:SELECT * FROM table ORDER BY c1, c2 LIMIT 10;如果c1已经排好序,那么只需要在此基础上对c2进行增量排序即可。PostgreSQL 13 版本新增了enable_incrementalsort参数控制是否开启增量排序,此参数默认开启,可以通过set enable_incremental_sort = off 关闭。下面我们在100万条数据的表上测试一下增量排序的效果:未打开增量排序:  打开增量排序:   未打开增量排序前,sql执行时间为222ms,打开增量排序之后,执行时间变为0.213ms,性能相比未开启增量排序时提升了好几个数量级。3.       支持并行VACUUM  PostgreSQL 13支持了对索引的并行VACUUM,可以通过指定parallel选项打开该功能。使用该功能存在如下限制:l  目前仅限于索引的并行vacuum,每个索引会分配一个vacuum worker。l  不支持在加上FULL选项后使用。l  只有在至少包含有2个及以上索引的表上使用parallel选项才有效。l  索引的大小超过min_parallel_index_scan_size下面我们准备一张包含300万条数据的表,表上建了两个索引,在PostgreSQL 13上对比下正常vacuum和并行vacuum的效果:先看在PostgreSQL 13正常vacuum的情况:再看下在PostgreSQL 13下并行vacuum的执行情况:从上图比较可以看到,启用并行vacuum之后时间由356ms减少到42ms,提升了8倍多。4.     可信插件        PostgreSQL 13允许 非superuser安装一些被指定为可信的插件到自己的数据库中,只要该用户拥有 CREATE 权限即可。之前的版本是当用户想安装一个插件的时候,必须具有superuser权限。在pg13里将不需要这样了:只要某个插件被标记为“trusted”,那么就不再需要superuser权限了。插件是否可信,取决于插件的control文件,只要在control文件里设置了trusted = true 那么该插件就是可信的。   我们创建一个普通用户,然后用该用户登录数据库去创建插件会失败:       然后我们在pg_stat_statements.control文件里加上trusted = true之后再去尝试就成功了:   5.       总结PostgreSQL 13带来了很多令人欣喜的新特性和优化,本文限于篇幅只介绍了其中4个。包括逻辑复制支持分区表,扩展统计信息,跟踪wal使用信息等很多很有意思的功能读者可以自行探索。详细说明请参考社区官方Release Notes:https://www.postgresql.org/docs/13/release-13.html
  • [技术干货] 【转载】技术实践丨PostgreSQL插件之pg_dirtyread “闪回查询“
     摘要:Oracle数据库有时候不小心删除掉数据,想查询这些数据,或者恢复数据,就可以使用带有as of子句的select语句进行闪回查询。PG粉有福了,下面介绍一种类似“闪回查询”插件 pg_dirtyread,可以读取未被vacuum的dead数据。github主页:https://github.com/df7cb/pg_dirtyread1.2 released:https://www.postgresql.org/message-id/20170923211004.uh27ncpjarkucrhd%40msg.credativ.de一、我们一起看下官网的3个例子:语法:SELECT * FROM pg_dirtyread('tablename') AS t(col1 type1, col2 type2, ...);样例1: 删除找回  CREATE EXTENSION pg_dirtyread;     -- Create table and disable autovacuum   CREATE TABLE foo (bar bigint, baz text);       ALTER TABLE foo SET (     autovacuum_enabled = false, toast.autovacuum_enabled = false   );  --测试方便,先把自动vacuum关闭掉。     INSERT INTO foo VALUES (1, 'Test'), (2, 'New Test');     DELETE FROM foo WHERE bar = 1;       SELECT * FROM pg_dirtyread('foo') as t(bar bigint, baz text);    bar   │   baz   ─────┼──────────        1     │ Test        2     │ New Test可以看到, 被删除的记录(1, 'Test')已经可以查询到。样例2:列被drop的情况 CREATE TABLE ab(a text, b text);     INSERT INTO ab VALUES ('Hello', 'World');       ALTER TABLE ab DROP COLUMN b;     DELETE FROM ab;       SELECT * FROM pg_dirtyread('ab') ab(a text, dropped_2 text);      a   │ dropped_2   ───────┼───────────    Hello │ World可以看到,虽然b列被drop掉了,但是仍然可以读取到数据。如何指定列:这里使用dropped_N来访问第N列,从1开始计数。局限:由于PG删除了原始列的元数据信息,因此需要在表列名中指定正确的类型,这样才能进行少量的完整性检查。包括类型长度、类型对齐、类型修饰符,并且采取的是按值传递。样例3:系统列SELECT * FROM pg_dirtyread('foo')            AS t(tableoid oid, ctid tid, xmin xid, xmax xid, cmin cid, cmax cid, dead boolean,            bar bigint, baz text);    tableoid │ ctid  │ xmin │ xmax │ cmin │ cmax │ dead │ bar │        baz   ──────────┼───────┼──────┼──────┼──────┼──────┼──────┼─────┼───────────────────         41823 │ (0,1) │ 1484 │ 1485 │    0 │    0 │ t    │   1 │ Delete   41823 │ (0,2) │ 1484 │    0 │    0 │    0 │ f    │   2 │ Insert         41823 │ (0,3) │ 1484 │ 1486 │    0 │    0 │ t    │   3 │ Update   41823 │ (0,4) │ 1484 │ 1488 │    0 │    0 │ f    │   4 │ Not deleted         41823 │ (0,5) │ 1484 │ 1489 │    1 │    1 │ f    │   5 │ Not updated         41823 │ (0,6) │ 1486 │    0 │    0 │    0 │ f    │   3 │ Updated         41823 │ (0,7) │ 1489 │    0 │    1 │    1 │ t    │   5 │ Not quite updated         41823 │ (0,8) │ 1490 │    0 │    2 │    2 │ t    │   6 │ Not inserted可以看到,xmax和ctid可以被恢复了。 oid只在11以及更早的版本中才能被恢复。二、支持的版本10和11已经支持,2.0以后的版本已经支持12和13,社区还是很活跃。三、实现分析核心代码有2部分:1、dirtyread_tupconvert.c 主要实现了dirtyread_convert_tuples_by_name,通过列名进行元组转换,处理列原信息被清理以及存在表继承的情况,关键部分是数组:attrMap[],下标从1开始。重点分析下dirtyread_do_convert_tupleHeapTuple dirtyread_do_convert_tuple(HeapTuple tuple, TupleConversionMap *map, TransactionId oldest_xmin) {       /*      * Extract all the values of the old tuple, offsetting the arrays so that      * invalues[0] is left NULL and invalues[1] is the first source attribute;      * this exactly matches the numbering convention in attrMap.      */     heap_deform_tuple(tuple, map->indesc, invalues + 1, inisnull + 1); //+1是因为是从下标1开始,从旧的元组中把数据的值获取到       /*      * Transpose into proper fields of the new tuple. 这部分是重点,在这里完成转换      */     for (i = 0; i < outnatts; i++)     {         int         j = attrMap;           if (j == DeadFakeAttributeNumber)          //场景1:明确是dead,直接调用内核的函数HeapTupleIsSurelyDead即可,         //定义在tqual.c中,其它场景可以使用HeapTupleSatisfiesVacuum、HeapTupleSatisfiesMVCC等等,这里明确是dead,所以使用HeapTupleIsSurelyDead         {             outvalues = HeapTupleIsSurelyDead(tuple                     , oldest_xmin);             outisnull = false;         }         else if (j < 0) //场景2:系统列,交给函数heap_getsysattr来处理。             outvalues = heap_getsysattr(tuple, j, map->indesc, &outisnull);         else         {   //场景3:最常见的场景,直接获取即可。             outvalues = invalues[j];             outisnull = inisnull[j];         }     }       return heap_form_tuple(map->outdesc, outvalues, outisnull); //重新包装为tuple格式 }2、pg_dirtyread.c 面向客户的接口在这里实现。重点分析下 Datum pg_dirtyread(PG_FUNCTION_ARGS)第1部分    if (SRF_IS_FIRSTCALL()),这部分比较套路化     {         superuser校验         PG_GETARG_OID获取表的oid         heap_open打开表         get_call_result_type计算结果校验,不支持复合类型         BlessTupleDesc(tupdesc) 拿到表结构         usr_ctx->map = dirtyread_convert_tuples_by_name(usr_ctx->reltupdesc,                         funcctx->tuple_desc, "Error converting tuple descriptors!");  //关键的一步,这里使用dirtyread_convert_tuples_by_name函数,。         heap_beginscan(usr_ctx->rel, SnapshotAny...),开始启动表扫描,这里使用了SnapshotAny        }第2部分,不断的获取每一行,然后对每一行进行转换,直到扫描结束。  if ((tuplein = heap_getnext(usr_ctx->scan, ForwardScanDirection)) != NULL)     {         if (usr_ctx->map != NULL)         {             tuplein = dirtyread_do_convert_tuple(tuplein, usr_ctx->map, usr_ctx->oldest_xmin);             SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuplein));         }         else             SRF_RETURN_NEXT(funcctx, heap_copy_tuple_as_datum(tuplein, usr_ctx->reltupdesc));     }     else     {         heap_endscan(usr_ctx->scan); //结束扫描         heap_close(usr_ctx->rel, AccessShareLock); //关闭表         SRF_RETURN_DONE(funcctx);     }整体上实现并不是很复杂,理解了这些后,就可以在此基础上增加自己的功能了。 而PG的魅力就在于此--架构的开放性,可以让开发者迅速地开发自己的“小程序”出来。
  • [技术干货] 技术实践丨PostgreSQL开启Huge Page场景分析
    PostgreSQL用户经常发现,服务端在连接数较大的情况下,会出现系统内存消耗过多的情况,严重者可能会造成OOM。但是服务端配置的共享内存(shared_buffers,wal_buffers等)是一定的,为什么内存会持续增加呢?这就与PostgreSQL的多进程架构有关了,下面我们来分析下。1. 大规格PG实例内存使用率较高分析为了保证物理内存能得到充分的利用,避免内存空间浪费,Linux把进程当前使用的内存部分加载到物理内存里,而不使用的部分则暂不加载。PostMaster进程注册共享内存时,系统只是分配一个虚拟的地址空间,并不直接分配物理内存。当有实际的内存访问时,CPU才会将虚拟地址映射到物理内存的一个地址上。维护这个映射关系的就是PageTable,它负责将虚拟内存地址转换成物理内存地址。Linux的内存管理采取的是分页存取机制:把较大的物理内存分为了一个个固定大小(4kB)的内存页进行管理。每块内存页通过PageTable中的一个元组来维护虚拟/物理内存之间的映射。CPU为了提高虚拟/物理内存之间的转换效率,也会在TLB中缓存一定量的Page Table元组。对于PostgreSQL这种多进程架构程序来说,当服务端使用的共享内存较大,且并发连接数较多时,由于操作系统对于每个进程都要维护单独的内存映射,PageTable中的元组数目将会变得非常多,所占用的内存大小也会特别大。2. Huge Page改善措施Linux为了应对这种场景,降低多进程下PageTable的内存消耗。自从2.6及以上内核版本提供了内存页大小为2MB的管理方式,称为Huge Page。如果使用Huge Page的话,相同物理内存使用量的情况下内存页的数目变少,减少了PageTable元组的条目个数,从而降低了系统的内存占用。作为世界上最先进的开源数据库,PostgreSQL也适配了Linux的Huge Page特性,服务端在注册共享内存时,会通过配置参数huge_pages来决定是否申请大页内存。postgresql.conf:huge_pages = on             -- 注册共享内存时必须使用大页huge_pages = try            -- 注册共享内存时首先考虑大页,若系统提供的大页内存不足时,则全部使用普通页huge_pages = off            -- 注册共享内存时不使用大页真实应用场景:某PG用户将实例(shared_buffers = 64GB)部署在一台内存为256GB的ECS上,业务繁忙时ECS内存使用率为85%,PageTable占用内存120GB。而开启Huge Page后相同业务场景的内存使用率降低到50%以下,PageTable大小仅300M!3. PG实例开启Huge Page操作步骤(1)查看操作系统的Huge Page大小grep Hugepage /proc/meminfo(2)估算PostgreSQL实例需要的Huge Page使用量:128GB/2MB * 1.2 = 78643(3)/etc/sysctl.conf中添加:vm.nr_hugepages = 78643(4)重新加载系统配置参数:sysctl –p(5)确认是否配置成功。可以看到Huge Page总数为78643(6)确认PG配置文件打开huge_pages(7)启动PostgreSQL服务端,可以看到系统中的空闲Huge Page已经减少,部分大页已经被共享内存使用。4. Huge Page使用建议虽然Huge Page在一定场景下可以改善服务端内存使用过高的情况,但不是鼓励所有的PG实例都使用大页,盲目的开启Huge Page可能引起服务端的性能下降。下面我们根据Huge Page的优缺点来分析下使用场景。Huge Page优势:(1)CPU的TLB可以缓存的物理地址空间更大,从而提升TLB的命中率,降低CPU负载;(2)Huge Page使用的内存是不可交换(swap)的,没有内存空间换入/换出的开销;(3)极大的减少了系统维护PageTable的内存开销。Huge Page劣势:(1)Huge Page使用的内存需要预先分配;(2)Huge Page使用固定大小的内存区域,不会被释放;(3)对于写密集型的场景,Huge Page会加大Cache写冲突的发生概率。所以强烈推荐PG实例开启Huge Page的场景:共享内存使用较大(>=8GB)且连接数较多(>= 500),并且热点数据分散。不推荐PG实例开启Huge Page的场景:写业务密集,热点数据集中且内存使用较小。5.PG开启Huge Page时的注意事项(1)当配置参数huge_pages设置为on时,若PG启动时需要注册的共享内存大于操作系统提供的Huge Page大小时,数据库将无法启动。推荐将huge_pages参数设置为try,在此种场景下,PostMaster将会改为申请普通内存。(2)修改shared_buffers/wal_buffers等共享内存相关的GUC参数时,需要重新计算操作系统所需的Huge Page数,以防服务端无法启动或者部分大页内存没有被使用且无法释放而造成浪费。
  • [技术干货] PostgreSQL开启Huge Page场景分析
        PostgreSQL用户经常发现,服务端在连接数较大的情况下,会出现系统内存消耗过多的情况,严重者可能会造成OOM。但是服务端配置的共享内存(shared_buffers,wal_buffers等)是一定的,为什么内存会持续增加呢?这就与PostgreSQL的多进程架构有关了,下面我们来分析下。1. 大规格PG实例内存使用率较高分析为了保证物理内存能得到充分的利用,避免内存空间浪费,Linux把进程当前使用的内存部分加载到物理内存里,而不使用的部分则暂不加载。PostMaster进程注册共享内存时,系统只是分配一个虚拟的地址空间,并不直接分配物理内存。当有实际的内存访问时,CPU才会将虚拟地址映射到物理内存的一个地址上。维护这个映射关系的就是PageTable,它负责将虚拟内存地址转换成物理内存地址。 Linux的内存管理采取的是分页存取机制:把较大的物理内存分为了一个个固定大小(4kB)的内存页进行管理。每块内存页通过PageTable中的一个元组来维护虚拟/物理内存之间的映射。CPU为了提高虚拟/物理内存之间的转换效率,也会在TLB中缓存一定量的Page Table元组。对于PostgreSQL这种多进程架构程序来说,当服务端使用的共享内存较大,且并发连接数较多时,由于操作系统对于每个进程都要维护单独的内存映射,PageTable中的元组数目将会变得非常多,所占用的内存大小也会特别大。2. Huge Page改善措施Linux为了应对这种场景,降低多进程下PageTable的内存消耗。自从2.6及以上内核版本提供了内存页大小为2MB的管理方式,称为Huge Page。如果使用Huge Page的话,相同物理内存使用量的情况下内存页的数目变少,减少了PageTable元组的条目个数,从而降低了系统的内存占用。作为世界上最先进的开源数据库,PostgreSQL也适配了Linux的Huge Page特性,服务端在注册共享内存时,会通过配置参数huge_pages来决定是否申请大页内存。postgresql.conf:    huge_pages = on             -- 注册共享内存时必须使用大页    huge_pages = try            -- 注册共享内存时首先考虑大页,若系统提供的大页内存不足时,则全部使用普通页    huge_pages = off            -- 注册共享内存时不使用大页真实应用场景:某PG用户将实例(shared_buffers = 64GB)部署在一台内存为256GB的ECS上,业务繁忙时ECS内存使用率为85%,PageTable占用内存120GB。而开启Huge Page后相同业务场景的内存使用率降低到50%以下,PageTable大小仅300M!3. PG实例开启Huge Page操作步骤    (1)查看操作系统的Huge Page大小grep Hugepage /proc/meminfo    (2)估算PostgreSQL实例需要的Huge Page使用量:128GB/2MB * 1.2 = 78643    (3)/etc/sysctl.conf中添加:vm.nr_hugepages = 78643    (4)重新加载系统配置参数:sysctl –p    (5)确认是否配置成功。可以看到Huge Page总数为78643    (6)确认PG配置文件打开huge_pages    (7)启动PostgreSQL服务端,可以看到系统中的空闲Huge Page已经减少,部分大页已经被共享内存使用。    4. Huge Page使用建议虽然Huge Page在一定场景下可以改善服务端内存使用过高的情况,但不是鼓励所有的PG实例都使用大页,盲目的开启Huge Page可能引起服务端的性能下降。下面我们根据Huge Page的优缺点来分析下使用场景。Huge Page优势:(1)CPU的TLB可以缓存的物理地址空间更大,从而提升TLB的命中率,降低CPU负载;(2)Huge Page使用的内存是不可交换(swap)的,没有内存空间换入/换出的开销;(3)极大的减少了系统维护PageTable的内存开销。Huge Page劣势:(1)Huge Page使用的内存需要预先分配;(2)Huge Page使用固定大小的内存区域,不会被释放;(3)对于写密集型的场景,Huge Page会加大Cache写冲突的发生概率。所以强烈推荐PG实例开启Huge Page的场景:共享内存使用较大(>=8GB)且连接数较多(>= 500),并且热点数据分散。不推荐PG实例开启Huge Page的场景:写业务密集,热点数据集中且内存使用较小。5.PG开启Huge Page时的注意事项(1)当配置参数huge_pages设置为on时,若PG启动时需要注册的共享内存大于操作系统提供的Huge Page大小时,数据库将无法启动。推荐将huge_pages参数设置为try,在此种场景下,PostMaster将会改为申请普通内存。(2)修改shared_buffers/wal_buffers等共享内存相关的GUC参数时,需要重新计算操作系统所需的Huge Page数,以防服务端无法启动或者部分大页内存没有被使用且无法释放而造成浪费。
  • [问题求助] 欧拉2.8是否支持docker安装postgresql 12.4
    鲲鹏欧拉2.8已安装docker,是否支持用docker安装postgresql 12.4数据库
  • [数据库] 全新增强4大特性,华为云PostgreSQL 12 正式商用~~
    全新增强4大特性,华为云PostgreSQL 12 正式商用PostgreSQL是世界上备受欢迎的一款典型开源关系型数据库,在保证数据可靠性和完整性方面尤为出色。为了给用户提供更稳定可靠的服务,华为云数据库团队经过精心研发,正式推出了RDS for PostgreSQL 12版本,并于日前开始商用。PostgreSQL 12自官方推出以来,在各方面都得到了加强,TPC-C 性能测试下,平均可以提升约40%的查询性能和空间利用率,特别是数据量较大情况下,用户可以以较小的成本换来性能和空间管理等存储特性,包括企业级安全、后台管理和SQL/JSON支持、生成列、优化WITH查询、授权控制、可插拔表存储接口等功能。华为云RDS for PostgreSQL 12除了具备官方的全新功能外,还针对华为云用户的特殊使用场景,设计了更为贴心的服务,极大提升了用户体验。华为云RDS for PostgreSQL 12的4大特性性能提升40%华为云RDS for PostgreSQL 12版本在性能和易维护性方面有了显著的增强,尤其是对索引和分区子系统,大大提升了各种操作访问/查询的效率。Ø  索引:对标准索引类型B树索引进行了优化,使其可以更好地处理索引更新频率较高类型的负载的总体性能。另外生成GiST、GIN或SP-GiST索引的WAL日志的负载显著减少,SP-GiST索引支持<->距离操作的K-NN(即相邻最近)查询,以及CREATE STATISTICS指令现在支持最常用值MCV 的统计来帮助那些字段值非均匀分布的查询生成更优化的查询计划。Ø  分区表:对分区表的查询也做了较大改进,特别是对那些有数千个分区的表,而结果只需从几个有限的分区提取数据的查询。PostgreSQL 12增强数据INSERT 和COPY方式加入分区表的操作,支持不阻塞查询的情况下新增分区。增强SQL一致性和功能华为云RDS for PostgreSQL 12版支持对JSON文档进行查询时使用JSON路径表达式的功能。对使用JSONB格式保存的文档,这些查询可以利用已有的索引机制来高效提取数据。支持WITH查询,可以实现非物化操作处理,这对很多现在已有的查询有很大帮助;引入“生成列”功能,支持将计算出来的生成列存储起来。增强授权控制华为云RDS for PostgreSQL 12扩展了安全方面的功能,增加了GSS接口,支持客户端和服务端的双向加密。增强系统管理PostgreSQL 12版的REINDEX CONCURRENTLY指令可以在不影响新的索引写入的前提下让用户执行重建索引操作,这有助于用户在不停机状态下实现对较大索引的重建。使用pg_checksums指令对停机的PostgreSQL来开启或关闭页校验功能,该功能有助于检查已写入磁盘的数据一致性,而以前版本中该操作仅允许在initdb的阶段来执行。此外,华为云RDS for PostgreSQL 12支持自动备份与恢复,支持对参数进行自定义设置,支持一键扩容,故障闪恢复,提供多种安全策略保护数据库和用户隐私。华为云RDS for PostgreSQL 12架构图适用更多场景华为云RDS for PostgreSQL 12版本提供了卓越的性能和功能,适用于位置应用系统、科研项目信息系统、金融保险系统、互联网电商等场景。位置应用系统华为云RDS for PostgreSQL 12支持PostGIS插件,提供空间对象、空间索引、空间操作函数和空间操作符等空间信息服务功能,非常适用于位置应用类产品。科研项目信息系统华为云RDS for PostgreSQL 12支持更复杂的数据类型,能够存储精确的数据,基于VPN进行数据私密保护,并且能够自定义数据类型。还可将不常用的数据转存到OBS云存储,节省存储成本和主机空间。金融保险系统华为云RDS for PostgreSQL 12使用多版本并发控制(MVCC)保证数据一致性,主备实例数据同步复制实现数据双保险,确保数据不丢失,并且配合OBS实现存储空间扩展,将冷数据转存到OBS中,进一步节省历史数据存储成本。互联网电商华为云RDS for PostgreSQL 12在互联网应用高并发场景下具有较高稳定性,并且所有操作都可以在SQL中完成,无需来回进行数据导入,提高开发效率。每一次的改进和优化都是对技术的追求和对客户的用心服务,华为云RDS for PostgreSQL 12版本的推出,更是对这一理念的具体实践,未来华为云数据库会提供更加优质的产品和服务,欢迎大家选购体验。
  • [技术干货] 40%性能提升,华为云推出PostgreSQL 12 商用版
    摘要:日前,华为云数据库正式推出了RDS for PostgreSQL 12版本,并开始商用。本文将从华为云RDS for PostgreSQL 12的4大特性和架构图等多方面来解读华为云PostgreSQL 12版本,帮助大家深入了解PostgreSQL 12版本的产品功能特性,更好的应用实施。全新增强4大特性,华为云PostgreSQL 12 正式商用PostgreSQL是世界上备受欢迎的一款典型开源关系型数据库,在保证数据可靠性和完整性方面尤为出色。为了给用户提供更稳定可靠的服务,华为云数据库团队经过精心研发,正式推出了RDS for PostgreSQL 12版本,并于日前开始商用。PostgreSQL 12自官方推出以来,在各方面都得到了加强,TPC-C 性能测试下,平均可以提升约40%的查询性能和空间利用率,特别是数据量较大情况下,用户可以以较小的成本换来性能和空间管理等存储特性,包括企业级安全、后台管理和SQL/JSON支持、生成列、优化WITH查询、授权控制、可插拔表存储接口等功能。华为云RDS for PostgreSQL 12除了具备官方的全新功能外,还针对华为云用户的特殊使用场景,设计了更为贴心的服务,极大提升了用户体验。华为云RDS for PostgreSQL 12的4大特性性能提升40%华为云RDS for PostgreSQL 12版本在性能和易维护性方面有了显著的增强,尤其是对索引和分区子系统,大大提升了各种操作访问/查询的效率。Ø  索引:对标准索引类型B树索引进行了优化,使其可以更好地处理索引更新频率较高类型的负载的总体性能。另外生成GiST、GIN或SP-GiST索引的WAL日志的负载显著减少,SP-GiST索引支持<->距离操作的K-NN(即相邻最近)查询,以及CREATE STATISTICS指令现在支持最常用值MCV 的统计来帮助那些字段值非均匀分布的查询生成更优化的查询计划。Ø  分区表:对分区表的查询也做了较大改进,特别是对那些有数千个分区的表,而结果只需从几个有限的分区提取数据的查询。PostgreSQL 12增强数据INSERT 和COPY方式加入分区表的操作,支持不阻塞查询的情况下新增分区。增强SQL一致性和功能华为云RDS for PostgreSQL 12版支持对JSON文档进行查询时使用JSON路径表达式的功能。对使用JSONB格式保存的文档,这些查询可以利用已有的索引机制来高效提取数据。支持WITH查询,可以实现非物化操作处理,这对很多现在已有的查询有很大帮助;引入“生成列”功能,支持将计算出来的生成列存储起来。增强授权控制华为云RDS for PostgreSQL 12扩展了安全方面的功能,增加了GSS接口,支持客户端和服务端的双向加密。增强系统管理PostgreSQL 12版的REINDEX CONCURRENTLY指令可以在不影响新的索引写入的前提下让用户执行重建索引操作,这有助于用户在不停机状态下实现对较大索引的重建。使用pg_checksums指令对停机的PostgreSQL来开启或关闭页校验功能,该功能有助于检查已写入磁盘的数据一致性,而以前版本中该操作仅允许在initdb的阶段来执行。此外,华为云RDS for PostgreSQL 12支持自动备份与恢复,支持对参数进行自定义设置,支持一键扩容,故障闪恢复,提供多种安全策略保护数据库和用户隐私。华为云RDS for PostgreSQL 12架构图适用更多场景华为云RDS for PostgreSQL 12版本提供了卓越的性能和功能,适用于位置应用系统、科研项目信息系统、金融保险系统、互联网电商等场景。位置应用系统华为云RDS for PostgreSQL 12支持PostGIS插件,提供空间对象、空间索引、空间操作函数和空间操作符等空间信息服务功能,非常适用于位置应用类产品。科研项目信息系统华为云RDS for PostgreSQL 12支持更复杂的数据类型,能够存储精确的数据,基于VPN进行数据私密保护,并且能够自定义数据类型。还可将不常用的数据转存到OBS云存储,节省存储成本和主机空间。金融保险系统华为云RDS for PostgreSQL 12使用多版本并发控制(MVCC)保证数据一致性,主备实例数据同步复制实现数据双保险,确保数据不丢失,并且配合OBS实现存储空间扩展,将冷数据转存到OBS中,进一步节省历史数据存储成本。互联网电商华为云RDS for PostgreSQL 12在互联网应用高并发场景下具有较高稳定性,并且所有操作都可以在SQL中完成,无需来回进行数据导入,提高开发效率。每一次的改进和优化都是对技术的追求和对客户的用心服务,华为云RDS for PostgreSQL 12版本的推出,更是对这一理念的具体实践,未来华为云数据库会提供更加优质的产品和服务,欢迎大家选购体验。偷偷告诉你,除了上面的特性解读,我们还特邀了专家线上面对面直播详解,更多华为云PostgreSQL 12 的强大功能等你解锁,戳下方二维码,快来报名观看直播吧!
  • [热门活动] 【华为云•微话题】PostgreSQL 12首发之际,吐槽or赞美?来来,走一波,参与即可赢取U型枕&amp;双肩包
    【直播回看】华为云PostgreSQL 12正式商用,特邀华为云数据库专家Willie为你讲解PostgreSQL业内地位、华为云PostgreSQL 12亮点、架构及关键特性。福利来啦:看直播,学知识,互动赢无线鼠标,下单还有机械键盘和蓝牙耳机哦直播链接:https://huaweicloud.bugu.mudu.tv/watch/lm0rk1dm【微话题活动】PostgreSQL经过20+年的开源发展,2017、2018连续2年被DB-Engines评选为 "年度优秀数据库”,2019年度又被OSCON国际开源组织评为“终身成就奖”的开源产品。华为云PostgreSQL 12已正式商用发布,在各方面都得到了加强,包括企业级安全、后台管理和SQL/JSON支持、生成列、优化WITH查询、授权控制、可插拔表存储接口等功能。尤其突出的是,查询性能和空间利用率平均提升了约40%,在数据量较大情况下,用户可以以较小的成本换取处理性能和空间管理。今天我们邀请到华为云数据库产品管理专家Willie和大家讨论一下:【PostgreSQL 12首发之际,吐槽or赞美?】活动时间2020年5月9日-2020年5月22日参与方式直接在本帖回复关于以下问题的理解或评论1、您从事什么行业,为什么使用或计划使用PostgreSQL数据库?2、您在使用过程中,发现PostgreSQL数据库目前存在的问题有哪些?3、华为云PostgreSQL 12商用发布后,是否可以解决您的问题?4、华为云PostgreSQL 12支持ARM版本,会给行业和您的工作带来什么价值?5、您觉得华为云PostgreSQL在目前的市面上有什么差异性优势,未来应该加强什么?本期奖品A.回帖参与本次讨论,回复与话题相关的原创内容,即可获得U型枕1个(数量有限,先到先得)。B.数据库产品管理专家Willie评出3名优质评论奖,各送出华为云定制双肩包1个。(两样奖品不可同时获得,奖品于活动结束发放) 评奖标准回复话题数量和内容质量                                                                                                        优质评论奖3名                                                                              参与奖
  • [热门活动] 【福利贴】华为云PostgreSQL 12首发强势特性解析专场直播,微信转发后回复盖楼赢好礼
    【直播主题】:华为云PostgreSQL 12正式商用,Willie直播详解首发“酷炫”特性【直播看点】:Part 1:PostgreSQL 12亮点大揭秘Part 2:PostgreSQL 12架构及关键特性剖析Part 3:PostgreSQL特惠活动攻略             云数据库组合推荐与购买攻略             互动抽奖与直播福利【直播时间】:5月19日 19:00-20:00【报名链接】:https://bbs.huaweicloud.com/signup/b9ebd73ade5142efb50f48c648fcdf53【直播福利】颈枕 8个、无线鼠标 3个、雷柏机械键盘 6个、HUAWEI FreeBuds悦享版无线耳机 1个更有直播专享PG1元尝鲜价 100个,五折优购(满3000元减1500元满减券 50个、满1000元减500元满减券 50个、满500元减200元满减券 50个)欢迎大家参与和转发~——————————————————————我是分割线——————————————————————————当当当当~~最后公布本帖福利即日起至5月19日 18:00 分享此长图到朋友圈,并截图回复此贴即可(此贴已设置仅楼主可见)5月14日、5月15日、5月18日,连续三天,每天抽取1名幸运小伙伴,赠送颈枕一个噢中奖公示:5月20日,在此处公示赶快行动起来吧~中奖人员公示:日期获奖人员5月14日加油O幸福5月15日小伙贼奔放5月18日yhl请获奖用户在5日内添加小助手微信(cloud_xiaolu)领奖,否则视为放弃奖励不予补发。注:若收货地址为中国大陆地区,则邮费论坛承担;若收货地址为港澳台地区及海外地区,则邮费需要您自行承担。
  • [热门活动] 【福利贴】华为云PostgreSQL 12首发强势特性解析专场直播,点赞吐槽互动赢好礼
    【直播主题】:华为云PostgreSQL 12正式商用,Willie直播详解首发“酷炫”特性【直播看点】:Part 1:PostgreSQL 12炫酷特性详解            PostgreSQL简介和应用场景            PostgreSQL 12架构及关键特性剖析            PostgreSQL应用案例Part 2:PostgreSQL特惠活动攻略             云数据库组合推荐与购买攻略             互动抽奖与直播福利【直播时间】:5月19日 19:00-20:00【直播链接】:https://bbs.huaweicloud.com/signup/b9ebd73ade5142efb50f48c648fcdf53【直播福利】颈枕 8个、无线鼠标 3个、雷柏机械键盘 6个、HUAWEI FreeBuds悦享版无线耳机 1个更有直播专享PG1元尝鲜价 100个,五折优购(满3000元减1500元满减券 50个、满1000元减500元满减券 50个、满500元减200元满减券 50个)欢迎大家参与和转发~——————————————————————我是分割线——————————————————————————当当当当~~最后公布本帖福利在此贴盖楼,回复一句关于数据库的话可以是学习心得、自我感悟,对华为云数据库产品建议,学习诉求等,均可举例:华为云数据库xxx用着很棒我希望华为云数据库定期举办xxx活动第33、66、99、150、200楼的童鞋即可获得颈枕一个噢如有重复中奖,顺延至下一楼层的未中奖用户中奖公示:5月22日,在本帖二楼公示赶快行动起来吧~中奖人员公示:楼层获奖人员33楼啊酒哥哥66楼hw84820715请获奖用户在5日内添加小助手微信(cloud_xiaolu)领奖,否则视为放弃奖励不予补发。注:若收货地址为中国大陆地区,则邮费论坛承担;若收货地址为港澳台地区及海外地区,则邮费需要您自行承担。
  • [交流吐槽] 希望添加PostgreSQL镜像
    希望添加PostgreSQL的Linux repo仓库,官方上游仓库: https://ftp.postgresql.org/pub/或者: https://www.postgresql.org/ftp/或者: https://download.postgresql.org/pub/另: 发现rsync地址: rsync://rsync.postgresql.org/pgsql-ftp通过rsync方案同步镜像应该更方便一些
  • [技术干货] 浅析PostgreSQL并行查询代价估算
    并行查询特性最早是在PostgreSQL 9.6中引入。自那时起,社区一直在扩展该功能。在PostgreSQL 11和PostgreSQL 12中,社区开发人员向数据库引擎添加了更多的相关功能。本文就PostgreSQL查询优化器对并行执行代价估算的工作原理进行阐述,不足之处希望大家多多指正。串行顺序扫描执行代价估算       为了方便解释,用一个简单的例子来说明问题。首先通过代码片段1创建一个表包含两列。    1.  //代码片段1     2.  mydb=# CREATE TABLE people (id int PRIMARY KEY NOT NULL, age int NOT NULL);      3.  CREATE TABLE为了演示并行查询带来的益处,利用代码片段2往表people**一千万条数据,其中age字段是0-100之间的随机数。    1.  //代码片段2     2.  mydb=# INSERT INTO people        3.         SELECT id, (random()*100)::integer AS age        4.         FROM generate_series(1,10000000) AS id;       5.  INSERT 0 10000000默认情况下PostgreSQL是打开并行执行的。我们首先关闭并行执行开关,检查串行查询执行的耗时。通过将配置参数max_parallel_workers_per_gather设置为0可以关闭并行执行特性。从查询执行计划可以看到,顺序扫描的执行代价为144.248ms(Pg的执行计划显示的时间由两部分组成,‘..’前面的称之为start_up_cost,后面部分叫做run_cost)。总的查询执行代价为169.248ms。Pg如何计算得到这些数字的? 1.  //代码片段3  2.  mydb=# SET max_parallel_workers_per_gather TO 0;    3.  SET    4.  mydb=# explain analyze select count(*) from people;    5.                                 QUERY PLAN    6.  --------------------------------------------------------------------------------  7.   Aggregate  (cost=169248.60..169248.61 rows=1 width=8) (actual time=1375.237..1375.237 rows=1 loops=1)    8.      -> Seq Scan on people(cost=0.00..144248.48 rows=10000048 width=0)    9.   (4 rows)Pg查询执行时间total_cost = start_up_cost + run_cost,具体来说pg的运行时的代价由以下的式子计算得到:                total_cost = cpu_run_cost + disk_run_cost                                   = (cpu_tuple_cost + cpu_operator_cost) × Ntuple + seq_page_cost×Npage (1)        其中cpu_tuple_cost是CPU传输该记录的代价;cpu_operator_cost指函数运算或其他操作符的开销。有了上述计算规则以后,可以通过Pg的元数据表pg_class查询表people相关统计信息,见代码片段4。可以得到Npage=44248,Ntuple = 10000048.Pg源代码的cost.h头文件定义了公式(1)相关的计算代价,见代码片段5:    1.  //代码片段4     2.  mydb=# SELECT relpages, reltuples FROM pg_class WHERE relname = 'people';       3.   relpages |   reltuples       4.   ----------+---------------       5.     44248 | 1.0000048e+07       6.  (1 row)计算代价如下:    1.  //代码片段5     2.  /* defaults for costsize.c's Cost parameters */       3.  /* NB: cost-estimation code should use the variables, not these constants! */       4.  /* If you change these, update backend/utils/misc/postgresql.sample.conf */       5.  #define DEFAULT_SEQ_PAGE_COST  1.0       6.  #define DEFAULT_RANDOM_PAGE_COST  4.0       7.  #define DEFAULT_CPU_TUPLE_COST  0.01       8.  #define DEFAULT_CPU_INDEX_TUPLE_COST 0.005       9.  #define DEFAULT_CPU_OPERATOR_COST  0.0025       10. #define DEFAULT_PARALLEL_TUPLE_COST 0.1       11. #define DEFAULT_PARALLEL_SETUP_COST  1000.0将代码片段5的计算代价,放入公式(1),我们可以得到顺序扫描的代价:                              total_cost = (cpu_tuple_cost)×Ntuple + seq_page_cost×Npage                        = 0.01×1.0000048e+07 + 1×44248                                 = 144248.48这就是代码片段3第8行的顺序执行代价。而总的执行代价,需要对每条元组进行count函数操作,因此需要加上cpu_operator_cost,因此聚集函数count的查询执行start_up_cost为:                              Start_up_cost = cpu_run_cost + disk_run_cost                               = (cpu_tuple_cost + cpu_operator_cost)×Ntuple + seq_page_cost×Npage (1)                       = (0.01 + 0.0025) ×1.0000048e+07 + 1×44248                               = 169248.6 (代码片段3第7行所示)最后,系统只需要对这条元组传输即可,因此总的查询执行代价为:                            total_cost = (cpu_tuple_cost)×Ntuple + start_up_cost                                       =  0.01 + 169248.6                                       =  169248.61(代码片段3第7行所示)并行顺序扫描执行代价估算现在我们将并行执行的特性打开令max_parallel_workers_per_gather=2,相应的执行计划如下:1.  //代码片段6 2.  mydb=# set max_parallel_workers_per_gather = 2;   3.  SET   4.  mydb=# explain analyze select count(*) from people;   5.                           QUERY PLAN   6.  ------------------------------------------------------------------------------------------------------------ 7.   Finalize Aggregate  (cost=97331.80..97331.81 rows=1 width=8) (actual time=524.896..524.896 rows=1 loops=1)   8.     ->  Gather  (cost=97331.58..97331.79 rows=2 width=8) (actual time=524.828..526.162 rows=3 loops=1)   9.           Workers Planned: 2   10.          Workers Launched: 2   11.          -> Partial Aggregate  (cost=96331.58..96331.59 rows=1 width=8)   12.                -> Parallel Seq Scan on people  (cost=0.00..85914.87 rows=4166687 width=0)   13.  Planning Time: 0.307 ms   14.  Execution Time: 526.209 ms   15. (8 rows)为了解释并行查询执行代价,我们首先看看不同进程(为什么用进程是历史原因)之间工作量的分配。当并发进程只有两个的时候,主进程需要将大部分时间花费在执行工作,当并行进程的增加,主进程逐渐将工作转向聚合部分结果。Pg的进程工作量分配正是建立在这个基础之上。具体的分配算法见代码片段7第22行-27行。并行执行的框架如图1所示。1.  //代码片段7 2.  static double   3.  get_parallel_divisor(Path *path)   4.  {   5.      double      parallel_divisor = path->parallel_workers;   6.     7.       /*  8.        * Early experience with parallel query suggests that when there is only 9.        * one worker, the leader often makes a very substantial contribution to 10.       * executing the parallel portion of the plan, but as more workers are  11.       * added, it does less and less, because it's busy reading tuples from the  12.       * workers and doing whatever non-parallel post-processing is needed.  By  13.       * the time we reach 4 workers, the leader no longer makes a meaningful  14.       * contribution.  Thus, for now, estimate that the leader spends 30% of  15.       * its time servicing each worker, and the remainder executing the  16.       * parallel plan.  17.       */   18.     if (parallel_leader_participation)   19.     {   20.         double      leader_contribution;   21.    22.         leader_contribution = 1.0 - (0.3 * path->parallel_workers);   23.         if (leader_contribution > 0)   24.             parallel_divisor += leader_contribution;   25.     }   26.    27.   return parallel_divisor;  28.  }                                                                                    图1.并行执行框架因此当并行执行的worker为2的时候,每个工作进程所分配得到的工作量为:10000048.0 / (2 + (1 – 0.3 * 2)) = 4166686.66 rows.这就是代码片段6第13行得到每个worker处理的元组(rows)数目。这里需要注意的是虽然是并行扫描但是IO代价仍然是按照全表扫描的代价计算。这主要是因为每个并发进程在同一份数据上按照block-by-block的方式顺序推进全局next指针,这等价于全表扫描。总结PostgreSQL的口号是开源数据库中最强大的关系型数据库系统。其实业界也一直将其称为开源数据库的oracle。此言不虚,因为很多企业客户在去“O”问题上选择用PostgreSQL替代Oracle。PostgreSQL不仅在语法上高度兼容Oracle而且在性能上也向Oracle靠拢,例如并行查询特性就是PostgreSQL引以为豪的特性之一。PostgreSQL实现了并行scan,merge-join,hash-join,以及partition-join等。这篇文章对PostgreSQL的并行查询进行了初步的分析,探讨了并行工作进程之间的工作量分配,查询执行代价的计算,以及并行查询的总体框架。后续我们计划对PostgreSQL的并行join算法进行深入探讨以更好地了解PostgreSQL的并行查询功能。
  • [迁移工具] Porting Advisor 移植 PostgreSQL,移植报告问题
    环境介绍:平台:X86 计算,通用计算增强型, c6.large.22vCPUs | 4GB, CentOS 7.6 64bit) 迁移工具:Porting-advisor-x86_64-linux-1.1.3.tar.gzhttps://www.postgresql.org/ftp/source/v11.3/ ,下载的PostgreSQL 11.3 版本源代码包 postgresql-11.3.tar.gz1、代码移植工具填写信息:2、经过迁移工具分析后,显示内容如下:3、但试验手册上的试验中显示:需要移植的依赖库 SO 文件、源文件、代码行数均为 0,说明postgresql-11.3 源码不需要修改,可以直接进行源码编译安装。 有点疑惑,不知是工具的问题还是实验手册的问题?实验手册图如下:
总条数:103 到第
上滑加载中