PostgreSQL TID及tuple slot

本文涉及的产品
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
云原生数据库 PolarDB MySQL 版,通用型 2核8GB 50GB
简介: PostgreSQL TID及tuple slot

1)postgresql默认存储的是堆表,数据按行存储在heap page中。行记录除了存储字段的值外还会存储对应的ctid即行号,表示在哪个页第几个记录。

2)进行select的时候也可以直接指定ctid进行扫描:heap handler中表访问方法的函数为table_tuple_fetch_row_version函数,它来完成通过ctid获取元组。

    postgres=# select *from t where ctid='(0,2)';
       id1 | id2 
    -----+-----
       2 | b
    (1 row)

    3)根据ctid扫描的堆栈为

      Breakpoint 4, table_tuple_fetch_row_version (rel=0xae9da164, tid=0xbfb2d4c6, snapshot=0x8c06364, slot=0x8c4b7f4) at ../../../src/include/access/tableam.h:1026
      1026    return rel->rd_tableam->tuple_fetch_row_version(rel, tid, snapshot, slot);
      (gdb) s
      heapam_fetch_row_version (relation=0xae9da164, tid=0xbfb2d4c6, snapshot=0x8c06364, slot=0x8c4b7f4) at heapam_handler.c:190
      190    BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
      (gdb) bt
      #0  heapam_fetch_row_version (relation=0xae9da164, tid=0xbfb2d4c6, snapshot=0x8c06364, slot=0x8c4b7f4) at heapam_handler.c:190
      #1  0x082f7e08 in table_tuple_fetch_row_version (rel=0xae9da164, tid=0xbfb2d4c6, snapshot=0x8c06364, slot=0x8c4b7f4) at ../../../src/include/access/tableam.h:1026
      #2  0x082f86ee in TidNext (node=0x8c4b67c) at nodeTidscan.c:386
      #3  0x082cbb1a in ExecScanFetch (node=0x8c4b67c, accessMtd=0x82f85bc <TidNext>, recheckMtd=0x82f8751 <TidRecheck>) at execScan.c:133
      #4  0x082cbb70 in ExecScan (node=0x8c4b67c, accessMtd=0x82f85bc <TidNext>, recheckMtd=0x82f8751 <TidRecheck>) at execScan.c:183
      #5  0x082f8784 in ExecTidScan (pstate=0x8c4b67c) at nodeTidscan.c:443
      #6  0x082c9d5f in ExecProcNodeFirst (node=0x8c4b67c) at execProcnode.c:445
      #7  0x082c10ef in ExecProcNode (node=0x8c4b67c) at ../../../src/include/executor/executor.h:239
      #8  0x082c319f in ExecutePlan (estate=0x8c4b554, planstate=0x8c4b67c, use_parallel_mode=false, operation=CMD_SELECT, sendTuples=true, numberTuples=0, direction=ForwardScanDirection, 
          dest=0x8b941dc, execute_once=true) at execMain.c:1646
      #9  0x082c1574 in standard_ExecutorRun (queryDesc=0x8bb3e34, direction=ForwardScanDirection, count=0, execute_once=true) at execMain.c:364
      #10 0x082c1411 in ExecutorRun (queryDesc=0x8bb3e34, direction=ForwardScanDirection, count=0, execute_once=true) at execMain.c:308
      #11 0x0846d38b in PortalRunSelect (portal=0x8bde6f4, forward=true, count=0, dest=0x8b941dc) at pquery.c:929
      #12 0x0846d0b0 in PortalRun (portal=0x8bde6f4, count=2147483647, isTopLevel=true, run_once=true, dest=0x8b941dc, altdest=0x8b941dc, completionTag=0xbfb2d886 "") at pquery.c:770
      #13 0x0846772a in exec_simple_query (query_string=0x8b922e4 "select *from t where ctid='(0,2)';") at postgres.c:1215
      #14 0x0846b7e4 in PostgresMain (argc=1, argv=0x8bb7fec, dbname=0x8b8f824 "postgres", username=0x8bb7f14 "pg") at postgres.c:4236
      #15 0x083db09d in BackendRun (port=0x8bb49b8) at postmaster.c:4431
      #16 0x083da896 in BackendStartup (port=0x8bb49b8) at postmaster.c:4122
      #17 0x083d6dff in ServerLoop () at postmaster.c:1704
      #18 0x083d674d in PostmasterMain (argc=1, argv=0x8b8d808) at postmaster.c:1377
      #19 0x0831d0f4 in main (argc=1, argv=0x8b8d808) at main.c:228

      4)而postgres=# set enable_tidscan=off;将这个参数关闭后,就不能通过TID快速进行行扫描了,会走全表扫描,即通过heap handler表方法方法heap_getnextslot函数获取元组。


      Breakpoint 1, heap_getnextslot (sscan=0x8c4c21c, direction=ForwardScanDirection, slot=0x8c4b774) at heapam.c:1351
      1351    HeapScanDesc scan = (HeapScanDesc) sscan;
      (gdb) bt
      #0  heap_getnextslot (sscan=0x8c4c21c, direction=ForwardScanDirection, slot=0x8c4b774) at heapam.c:1351
      #1  0x082f26c2 in table_scan_getnextslot (sscan=0x8c4c21c, direction=ForwardScanDirection, slot=0x8c4b774) at ../../../src/include/access/tableam.h:875
      #2  0x082f2764 in SeqNext (node=0x8c4b67c) at nodeSeqscan.c:80
      #3  0x082cbb1a in ExecScanFetch (node=0x8c4b67c, accessMtd=0x82f26e7 <SeqNext>, recheckMtd=0x82f2774 <SeqRecheck>) at execScan.c:133
      #4  0x082cbb9c in ExecScan (node=0x8c4b67c, accessMtd=0x82f26e7 <SeqNext>, recheckMtd=0x82f2774 <SeqRecheck>) at execScan.c:200
      #5  0x082f27a7 in ExecSeqScan (pstate=0x8c4b67c) at nodeSeqscan.c:112
      #6  0x082c9d5f in ExecProcNodeFirst (node=0x8c4b67c) at execProcnode.c:445
      #7  0x082c10ef in ExecProcNode (node=0x8c4b67c) at ../../../src/include/executor/executor.h:239
      #8  0x082c319f in ExecutePlan (estate=0x8c4b554, planstate=0x8c4b67c, use_parallel_mode=false, operation=CMD_SELECT, sendTuples=true, numberTuples=0, direction=ForwardScanDirection, 
          dest=0x8b941dc, execute_once=true) at execMain.c:1646
      #9  0x082c1574 in standard_ExecutorRun (queryDesc=0x8bb3e34, direction=ForwardScanDirection, count=0, execute_once=true) at execMain.c:364
      #10 0x082c1411 in ExecutorRun (queryDesc=0x8bb3e34, direction=ForwardScanDirection, count=0, execute_once=true) at execMain.c:308
      #11 0x0846d38b in PortalRunSelect (portal=0x8bde6f4, forward=true, count=0, dest=0x8b941dc) at pquery.c:929
      #12 0x0846d0b0 in PortalRun (portal=0x8bde6f4, count=2147483647, isTopLevel=true, run_once=true, dest=0x8b941dc, altdest=0x8b941dc, completionTag=0xbfb2d886 "") at pquery.c:770
      #13 0x0846772a in exec_simple_query (query_string=0x8b922e4 "select *from t where ctid='(0,2)';") at postgres.c:1215
      #14 0x0846b7e4 in PostgresMain (argc=1, argv=0x8bb7fec, dbname=0x8b8f824 "postgres", username=0x8bb7f14 "pg") at postgres.c:4236
      #15 0x083db09d in BackendRun (port=0x8bb49b8) at postmaster.c:4431
      #16 0x083da896 in BackendStartup (port=0x8bb49b8) at postmaster.c:4122
      #17 0x083d6dff in ServerLoop () at postmaster.c:1704
      #18 0x083d674d in PostmasterMain (argc=1, argv=0x8b8d808) at postmaster.c:1377
      #19 0x0831d0f4 in main (argc=1, argv=0x8b8d808) at main.c:228

      4)元组结构参考

      https://blog.csdn.net/yanzongshuai/article/details/84195910

      5)slot

      a)内存中slot结构如上图所示。TupleTableSlot为存储行记录的结构。从数据页读取出记录后,会将其存储到slot中,返回上层。

      b)BufferHeapTupleTableSlot结构中第一个成员为HeapTupleTableSlot,而HeapTupleTableSlot第一个成员为TupleTableSlot,为第一个成员方便进行类型强制转换。

      c)将TupleTableSlot传到上层后,上层强制转换成HeapTupleTableSlot,进而解析出他的第二个成员tuple,这个tuple的结构为HeapTupleData,包括:t_len:t_data的长度,t_self:TID了,t_tableOid:所属表的OID,t_data:这个为记录头及其数据。


      相关实践学习
      使用PolarDB和ECS搭建门户网站
      本场景主要介绍如何基于PolarDB和ECS实现搭建门户网站。
      阿里云数据库产品家族及特性
      阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
      目录
      相关文章
      |
      消息中间件 Java 关系型数据库
      实时计算 Flink版操作报错合集之从 PostgreSQL 读取数据并写入 Kafka 时,遇到 "initial slot snapshot too large" 的错误,该怎么办
      在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
      1123 0
      |
      关系型数据库 PostgreSQL 索引
      PostgreSQL通过索引获取heap tuple解析
      PostgreSQL通过索引获取heap tuple解析
      295 0
      |
      弹性计算 关系型数据库 数据库连接
      PostgreSQL 12 preview - Move max_wal_senders out of max_connections for connection slot handling
      标签 PostgreSQL , max_wal_senders , max_connections , sorry, too many clients already 背景 如果你需要使用PG的流复制,上游节点的max_wal_senders参数,用来限制这个节点同时最多可以有多少个wal sender进程。 包括逻辑复制、物理复制、pg_basebackup备份等,只要是使用stre
      435 0
      |
      SQL 关系型数据库 PostgreSQL
      PostgreSQL Heap Only Tuple - HOT (降低UPDATE引入的索引写IO放大)
      标签 PostgreSQL , Heap Only Tuple , HOT 背景 PostgreSQL目前默认的存储引擎在更新记录时,会在堆内产生一条新版本,旧版本在不需要使用后VACUUM回收,回收旧版本前,需要先回收所有关联这个版本的所有索引POINT。
      2715 0
      |
      关系型数据库 PostgreSQL
      PostgreSQL tuple alignment padding (行,字段对齐) - 对齐规则,以及如何选择字段顺序
      标签 PostgreSQL , 对齐 , 变长 , 行 , tuple , row , alignment , padding 背景 PostgreSQL tuple内部有ALIGN机制,因此字段顺序选择实际上也是有讲究的,选择不好,可能因为ALIGN导致占用空间放大。
      1175 0
      |
      关系型数据库 数据库 SQL
      |
      关系型数据库 PostgreSQL 固态存储
      |
      Java 关系型数据库 PostgreSQL
      |
      存储 关系型数据库 PostgreSQL
      PostgreSQL 基于行号(tid)的快速扫描
      PostgreSQL 自带的表是堆表,数据按行存储在HEAP PAGE中,在btree索引中,除了存储字段的value,还会存储对应的ctid(即行号),检索记录也是通过行号进行检索的呢。 因此通过行号是可以快速检索到记录的。行号的写法是(page_number, item_number),数据块
      6197 0

      推荐镜像

      更多