iis服务器助手广告广告
返回顶部
首页 > 资讯 > 数据库 >PostgreSQL中获取Tuple的分区键值函数是什么
  • 602
分享到

PostgreSQL中获取Tuple的分区键值函数是什么

2024-04-02 19:04:59 602人浏览 泡泡鱼
摘要

这篇文章主要介绍“postgresql中获取Tuple的分区键值函数是什么”,在日常操作中,相信很多人在Postgresql中获取Tuple的分区键值函数是什么问题上存在疑惑,小编查阅了各式资料,整理出简单

这篇文章主要介绍“postgresql中获取Tuple的分区键值函数是什么”,在日常操作中,相信很多人在Postgresql中获取Tuple的分区键值函数是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”PostgreSQL中获取Tuple的分区键值函数是什么”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

一、数据结构

ModifyTable
通过插入、更新或删除,将子计划生成的行应用到结果表。


typedef struct ModifyTable
{
    Plan        plan;
    CmdType     operation;      
    bool        canSetTag;      
    Index       nominalRelation;    
    Index       rootRelation;   
    bool        partColsUpdated;    
    List       *resultRelations;    
    int         resultRelIndex; 
    int         rootResultRelIndex; 
    List       *plans;          
    List       *withCheckOptionLists;   
    List       *returningLists; 
    List       *fdwPrivLists;   
    Bitmapset  *fdwDirectModifyPlans;   
    List       *rowMarks;       
    int         epqParam;       
    OnConflictAction onConflictAction;  
    List       *arbiterIndexes; 
    List       *onConflictSet;  
    node       *onConflictWhere;    
    Index       exclRelRTI;     
    List       *exclRelTlist;   
} ModifyTable;

ResultRelInfo
ResultRelInfo结构体
每当更新一个现有的关系时,我们必须更新关系上的索引,也许还需要触发触发器。ResultRelInfo保存关于结果关系所需的所有信息,包括索引。


typedef struct ResultRelInfo
{
    NodeTag     type;

    
    //RTE索引
    Index       ri_RangeTableIndex;

    
    //结果/目标relation的描述符
    Relation    ri_RelationDesc;

    
    //目标关系中索引数目
    int         ri_NumIndices;

    
    //索引的关系描述符数组(索引视为一个relation)
    RelationPtr ri_IndexRelationDescs;

    
    //索引的键/属性数组
    IndexInfo **ri_IndexRelationInfo;

    
    //触发的索引
    TriggerDesc *ri_TrigDesc;

    
    //触发器函数(缓存)
    FmgrInfo   *ri_TrigFunctions;

    
    //WHEN表达式状态的触发器数组
    ExprState **ri_TrigWhenExprs;

    
    //可选的触发器运行期度量器
    Instrumentation *ri_TrigInstrument;

    
    //FDW回调函数
    struct FdwRoutine *ri_FdwRoutine;

    
    //可用于存储FDW的私有状态
    void       *ri_FdwState;

    
    //直接更新FDW时为T
    bool        ri_usesFdwDirectModify;

    
    //WithCheckOption链表
    List       *ri_WithCheckOptions;

    
    //WithCheckOption表达式链表
    List       *ri_WithCheckOptionExprs;

    
    //约束检查表达式状态数组
    ExprState **ri_ConstraintExprs;

    
    //用于从元组中删除junk属性
    JunkFilter *ri_junkFilter;

    
    //RETURNING表达式链表
    List       *ri_returningList;

    
    //用于计算RETURNING链表
    ProjectionInfo *ri_projectReturning;

    
    //用于检查冲突的仲裁器索引的列表
    List       *ri_onConflictArbiterIndexes;

    
    //ON CONFLICT解析状态
    OnConflictSetState *ri_onConflict;

    
    //分区检查表达式链表
    List       *ri_PartitionCheck;

    
    //分区检查表达式状态
    ExprState  *ri_PartitionCheckExpr;

    
    //分区root根表描述符
    Relation    ri_PartitionRoot;

    
    //额外的分区元组路由信息
    struct PartitionRoutingInfo *ri_PartitionInfo;
} ResultRelInfo;

PartitionRoutingInfo
PartitionRoutingInfo结构体
分区路由信息,用于将元组路由到表分区的结果关系信息。


typedef struct PartitionRoutingInfo
{
    
    TupleConversionMap *pi_RootToPartitionMap;

    
    TupleConversionMap *pi_PartitionToRootMap;

    
    TupleTableSlot *pi_PartitionTupleSlot;
} PartitionRoutingInfo;

TupleConversionMap
TupleConversionMap结构体,用于存储元组转换映射信息.

typedef struct TupleConversionMap
{
    TupleDesc   indesc;         
    TupleDesc   outdesc;        
    AttrNumber *attrMap;        
    Datum      *invalues;       
    bool       *inisnull;       //是否为NULL标记数组
    Datum      *outvalues;      
    bool       *outisnull;      //null标记
} TupleConversionMap;

二、源码解读

FORMPartitionKeyDatum函数获取Tuple的分区键值,返回键值values[]数组和是否为null标记isnull[]数组.


static void
FormPartitionKeyDatum(PartitionDispatch pd,
                      TupleTableSlot *slot,
                      EState *estate,
                      Datum *values,
                      bool *isnull)
{
    ListCell   *partexpr_item;
    int         i;

    if (pd->key->partexprs != NIL && pd->keystate == NIL)
    {
        
        //检查调用者是否已正确配置内存上下文
        Assert(estate != NULL &&
               GetPerTupleExprContext(estate)->ecxt_scantuple == slot);

        
        //第一次进入,配置表达式解析器状态
        pd->keystate = ExecPrepareExprList(pd->key->partexprs, estate);
    }

    partexpr_item = list_head(pd->keystate);//获取分区键表达式状态
    for (i = 0; i < pd->key->partnatts; i++)//循环遍历分区键
    {
        AttrNumber  keycol = pd->key->partattrs[i];//分区键属性编号
        Datum       datum;// typedef uintptr_t Datum;sizeof(Datum) == sizeof(void *) == 4 or 8
        bool        isNull;//是否null

        if (keycol != 0)//编号不为0
        {
            
            //扁平列,直接从堆元组中提取值
            datum = slot_getattr(slot, keycol, &isNull);
        }
        else
        {
            
            //表达式,需要解析
            if (partexpr_item == NULL)//分区键表达式状态为NULL,报错
                elog(ERROR, "wrong number of partition key expressions");
            //获取表达式值
            datum = ExecEvalExprSwitchContext((ExprState *) lfirst(partexpr_item),
                                              GetPerTupleExprContext(estate),
                                              &isNull);
            //切换至下一个
            partexpr_item = lnext(partexpr_item);
        }
        values[i] = datum;//赋值
        isnull[i] = isNull;
    }

    if (partexpr_item != NULL)//参数设置有误?报错
        elog(ERROR, "wrong number of partition key expressions");
}




static inline Datum
slot_getattr(TupleTableSlot *slot, int attnum,
             bool *isnull)
{
    AssertArg(attnum > 0);

    if (attnum > slot->tts_nvalid)
        slot_getsomeattrs(slot, attnum);

    *isnull = slot->tts_isnull[attnum - 1];

    return slot->tts_values[attnum - 1];
}



static inline void
slot_getsomeattrs(TupleTableSlot *slot, int attnum)
{
    if (slot->tts_nvalid < attnum)
        slot_getsomeattrs_int(slot, attnum);
}



void
slot_getsomeattrs_int(TupleTableSlot *slot, int attnum)
{
    
    //检查调用者输入参数是否有误
    Assert(slot->tts_nvalid < attnum); 
    Assert(attnum > 0);
    //attnum参数判断
    if (unlikely(attnum > slot->tts_tupleDescriptor->natts))
        elog(ERROR, "invalid attribute number %d", attnum);

    
    //从元组中获取尽可能多的属性。
    slot->tts_ops->getsomeattrs(slot, attnum);

    
    if (unlikely(slot->tts_nvalid < attnum))
    {
        slot_getmissingattrs(slot, slot->tts_nvalid, attnum);
        slot->tts_nvalid = attnum;
    }
}

三、跟踪分析

测试脚本如下

-- Hash Partition
drop table if exists t_hash_partition;
create table t_hash_partition (c1 int not null,c2  varchar(40),c3 varchar(40)) partition by hash(c1);
create table t_hash_partition_1 partition of t_hash_partition for values with (modulus 6,remainder 0);
create table t_hash_partition_2 partition of t_hash_partition for values with (modulus 6,remainder 1);
create table t_hash_partition_3 partition of t_hash_partition for values with (modulus 6,remainder 2);
create table t_hash_partition_4 partition of t_hash_partition for values with (modulus 6,remainder 3);
create table t_hash_partition_5 partition of t_hash_partition for values with (modulus 6,remainder 4);
create table t_hash_partition_6 partition of t_hash_partition for values with (modulus 6,remainder 5);

insert into t_hash_partition(c1,c2,c3) VALUES(20,'HASH0','HAHS0');

启动gdb,设置断点

(gdb) b FormPartitionKeyDatum
Breakpoint 5 at 0x6e30d2: file execPartition.c, line 1087.
(gdb) b slot_getattr
Breakpoint 6 at 0x489d9b: file heaptuple.c, line 1510.
(gdb) c
Continuing.

Breakpoint 5, FormPartitionKeyDatum (pd=0x2e1bfa0, slot=0x2e1b8a0, estate=0x2e1aeb8, values=0x7fff4e2407a0, 
    isnull=0x7fff4e240780) at execPartition.c:1087
1087        if (pd->key->partexprs != NIL && pd->keystate == NIL)

循环,根据分区键获取相应的键值

1087        if (pd->key->partexprs != NIL && pd->keystate == NIL)
(gdb) n
1097        partexpr_item = list_head(pd->keystate);
(gdb) 
1098        for (i = 0; i < pd->key->partnatts; i++)
(gdb) 
1100            AttrNumber  keycol = pd->key->partattrs[i];
(gdb) 
1104            if (keycol != 0)
(gdb) 
1107                datum = slot_getattr(slot, keycol, &isNull);

进入函数slot_getattr

(gdb) step

Breakpoint 6, slot_getattr (slot=0x2e1b8a0, attnum=1, isnull=0x7fff4e240735) at heaptuple.c:1510
1510        HeapTuple   tuple = slot->tts_tuple;

获取结果,分区键值为20

...
(gdb) p *isnull
$31 = false
(gdb) p slot->tts_values[attnum - 1]
$32 = 20

返回到FormPartitionKeyDatum函数中

(gdb) n
1593    }
(gdb) 
FormPartitionKeyDatum (pd=0x2e1bfa0, slot=0x2e1b8a0, estate=0x2e1aeb8, values=0x7fff4e2407a0, isnull=0x7fff4e240780)
    at execPartition.c:1119
1119            values[i] = datum;

完成调用

1119            values[i] = datum;
(gdb) n
1120            isnull[i] = isNull;
(gdb) 
1098        for (i = 0; i < pd->key->partnatts; i++)
(gdb) 
1123        if (partexpr_item != NULL)
(gdb) 
1125    }
(gdb) 
ExecFindPartition (resultRelInfo=0x2e1b108, pd=0x2e1c5b8, slot=0x2e1b8a0, estate=0x2e1aeb8) at execPartition.c:282
282         if (partdesc->nparts == 0)

到此,关于“PostgreSQL中获取Tuple的分区键值函数是什么”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

您可能感兴趣的文档:

--结束END--

本文标题: PostgreSQL中获取Tuple的分区键值函数是什么

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

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

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • oracle怎么查询当前用户所有的表
    要查询当前用户拥有的所有表,可以使用以下 sql 命令:select * from user_tables; 如何查询当前用户拥有的所有表 要查询当前用户拥有的所有表,可以使...
    99+
    2024-05-14
    oracle
  • oracle怎么备份表中数据
    oracle 表数据备份的方法包括:导出数据 (exp):将表数据导出到外部文件。导入数据 (imp):将导出文件中的数据导入表中。用户管理的备份 (umr):允许用户控制备份和恢复过程...
    99+
    2024-05-14
    oracle
  • oracle怎么做到数据实时备份
    oracle 实时备份通过持续保持数据库和事务日志的副本来实现数据保护,提供快速恢复。实现机制主要包括归档重做日志和 asm 卷管理系统。它最小化数据丢失、加快恢复时间、消除手动备份任务...
    99+
    2024-05-14
    oracle 数据丢失
  • oracle怎么查询所有的表空间
    要查询 oracle 中的所有表空间,可以使用 sql 语句 "select tablespace_name from dba_tablespaces",其中 dba_tabl...
    99+
    2024-05-14
    oracle
  • oracle怎么创建新用户并赋予权限设置
    答案:要创建 oracle 新用户,请执行以下步骤:以具有 create user 权限的用户身份登录;在 sql*plus 窗口中输入 create user identified ...
    99+
    2024-05-14
    oracle
  • oracle怎么建立新用户
    在 oracle 数据库中创建用户的方法:使用 sql*plus 连接数据库;使用 create user 语法创建新用户;根据用户需要授予权限;注销并重新登录以使更改生效。 如何在 ...
    99+
    2024-05-14
    oracle
  • oracle怎么创建新用户并赋予权限密码
    本教程详细介绍了如何使用 oracle 创建一个新用户并授予其权限:创建新用户并设置密码。授予对特定表的读写权限。授予创建序列的权限。根据需要授予其他权限。 如何使用 Oracle 创...
    99+
    2024-05-14
    oracle
  • oracle怎么查询时间段内的数据记录表
    在 oracle 数据库中查询指定时间段内的数据记录表,可以使用 between 操作符,用于比较日期或时间的范围。语法:select * from table_name wh...
    99+
    2024-05-14
    oracle
  • oracle怎么查看表的分区
    问题:如何查看 oracle 表的分区?步骤:查询数据字典视图 all_tab_partitions,指定表名。结果显示分区名称、上边界值和下边界值。 如何查看 Oracle 表的分区...
    99+
    2024-05-14
    oracle
  • oracle怎么导入dump文件
    要导入 dump 文件,请先停止 oracle 服务,然后使用 impdp 命令。步骤包括:停止 oracle 数据库服务。导航到 oracle 数据泵工具目录。使用 impdp 命令导...
    99+
    2024-05-14
    oracle
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作