暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PostgreSQL 14 preview - tid range scan方法, 一种page级别应用可自控的并行扫描、处理方法, 结合RR snapshot export功能

digoal 2021-01-02
1658

作者

digoal

日期

2021-02-28

标签

PostgreSQL , page tid scan , tid range scan


背景

什么是TID?

可以参考PG的page layout, heap table是以page来组织的, 每个page里面若干tuple. TID 是tuple的寻址地址: (pageid, itemid), pageid即第几个数据块, itemid即这个page内的第几条记录.
例如pagesize=8k时, tid=(10,1)表示第11个数据块的第一条记录. (page从0开始, item从1开始)

postgres=# create table tidtest(id int, info text); CREATE TABLE postgres=# insert into tidtest select generate_series(1,10000), md5(Random()::text); INSERT 0 10000 postgres=# select ctid,* from tidtest limit 1000; ctid | id | info ---------+-----+---------------------------------- (0,1) | 1 | 37118b76c2b8c62f78e785d52403f173 (0,2) | 2 | 14ff83346ede4618d14b66822387c710 (0,3) | 3 | a208b625a31d192e5e39bdf26a76adbb ...... (0,119) | 119 | fcb98794a1a326382954f1faddf27386 (0,120) | 120 | 0f5616b4c4d620095f0fefc5e767fb22 (1,1) | 121 | 8d9300a963198f97bacdfb2850192557 (1,2) | 122 | 15d1e0f71388652b15fa1c20a440f0bb ....

PostgreSQL 14以前的版本支持tid scan, 即, 我们可以直接指定要查询的行号. 他只需要扫描一个page. 通过itemid offset直接拿到tuple, 所以速度非常快.

```
postgres=# select ctid,* from tidtest where ctid='(10,1)';
ctid | id | info
--------+------+----------------------------------
(10,1) | 1201 | 598591b1b45498bdbc05c5aea2cb09e3
(1 row)

postgres=# explain select ctid,* from tidtest where ctid='(10,1)';
QUERY PLAN


Tid Scan on tidtest (cost=0.00..1.11 rows=1 width=43)
TID Cond: (ctid = '(10,1)'::tid)
(2 rows)
```

那么有没有可能一次获取一个page的数据呢?

PostgreSQL 14可以了

https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=bb437f995d47405ecd92cf66df71f7f7e40ed460

```
Add TID Range Scans to support efficient scanning ranges of TIDs
author David Rowley drowley@postgresql.org
Sat, 27 Feb 2021 09:59:36 +0000 (22:59 +1300)
committer David Rowley drowley@postgresql.org
Sat, 27 Feb 2021 09:59:36 +0000 (22:59 +1300)
commit bb437f995d47405ecd92cf66df71f7f7e40ed460
tree 0ee50f8a501e1ecc30d5cfd0eeb6ed0bcd41e2b2 tree | snapshot
parent f4adc41c4f92cc91d507b19e397140c35bb9fd71 commit | diff
Add TID Range Scans to support efficient scanning ranges of TIDs

This adds a new executor node named TID Range Scan. The query planner
will generate paths for TID Range scans when quals are discovered on base
relations which search for ranges on the table's ctid column. These
ranges may be open at either end. For example, WHERE ctid >= '(10,0)';
will return all tuples on page 10 and over.

To support this, two new optional callback functions have been added to
table AM. scan_set_tidrange is used to set the scan range to just the
given range of TIDs. scan_getnextslot_tidrange fetches the next tuple
in the given range.

For AMs were scanning ranges of TIDs would not make sense, these functions
can be set to NULL in the TableAmRoutine. The query planner won't
generate TID Range Scan Paths in that case.

Author: Edmund Horner, David Rowley
Reviewed-by: David Rowley, Tomas Vondra, Tom Lane, Andres Freund, Zhihong Yu
Discussion: https://postgr.es/m/CAMyN-kB-nFTkF=VA_JPwFNo08S0d-Yk0F741S2B7LDmYAi8eyA@mail.gmail.com
```

select * from tidtest where ctid >= '(10,0)' and ctid < '(11,0)';

range tid scan有什么应用? 我暂时能想到的, 例如

  • 1、应用层控制的并行全表数据处理.
  • 2、随机的PAGE级别数据查询.
  • 3、并行全表数据更新.
  • 4、随机的行级数据返回.

建议先学习一下snapshot export技术:

《PostgreSQL 块级 snapshot (flash back) - postgrespro improvement》

《londiste3 copy table' snapshot & PostgreSQL logical replication's snapshot 不同之处》

《PostgreSQL 9.5 new feature - pg_dump use --snapshot taken by another session (exp. slot, pg_export_snapshot())》

《PostgreSQL 事务快照功能 - Parallel Export consistent data or Parallel Query use snapshot transaction feature》

《PostgreSQL 共享事务快照功能 - PostgreSQL 9.2 can share snapshot between multi transactions》

《PostgreSQL 并行逻辑备份与一致性讲解 - PostgreSQL 9.3 parallel pg_dump》

并行全表数据更新例子

1、main session:

启动rr事务:

postgres=# begin isolation level repeatable read ; BEGIN

导出rr事务id:

```
postgres=*# select pg_export_snapshot();
pg_export_snapshot


00000003-00323878-1
(1 row)
```

查询被处理的表总共有多少个数据块:

```
postgres=*# select relpages from pg_class where oid='tidtest'::Regclass;
relpages


   8400

(1 row)
```

处理0-99号PAGEID:

update tidtest set info='new'||info where ctid >= '(0,0)' and ctid < '(100,0)';

2、other parallel sessions:

每个session 启动rr事务:

postgres=# begin isolation level repeatable read ; BEGIN

每个session 导入rr事务ID:

postgres=*# SET TRANSACTION SNAPSHOT '00000003-00323878-1'; SET

每个session 处理100个连续的pageid如100-199, 200-299, ... :

update tidtest set info='new'||info where ctid >= '(100,0)' and ctid < '(200,0)'; ...

随机返回记录

1、可以使用随机采样方法:

《PostgreSQL 随机采样应用 - table sample, tsm_system_rows, tsm_system_time》

《PostgreSQL 随机记录返回 - 300倍提速实践 (随机数组下标代替order by random())》

《随机记录并发查询与更新(转移、删除)的"无耻"优化方法》

2、也可以使用tid range scan(相比以上方法缺陷是某些PAGE可能没有有效记录, 例如都是dead tuple):

返回某一个或连续N个数据块的数据

select ctid,* from tidtest where ctid>='输入变量1' and ctid<'输入变量2';

返回N条数据, 并且要求这N条数据来自不同的数据块

select * from tidtest where ctid='输入变量1' or ctid='输入变量2' or ctid='输入变量3' ... ...;

返回同一个数据块的N条数据

select * from tidtest where ctid>='输入变量1' and ctid<'输入变量2' limit N;

PostgreSQL 许愿链接

您的愿望将传达给PG kernel hacker、数据库厂商等, 帮助提高数据库产品质量和功能, 说不定下一个PG版本就有您提出的功能点. 针对非常好的提议,奖励限量版PG文化衫、纪念品、贴纸、PG热门书籍等,奖品丰富,快来许愿。开不开森.

9.9元购买3个月阿里云RDS PostgreSQL实例

PostgreSQL 解决方案集合

德哥 / digoal's github - 公益是一辈子的事.

digoal's wechat

文章转载自digoal,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论