PostgreSQL思考---元组何时可以被删除?

PostgreSQL思考—元组何时可以被删除?

预备知识

PostgreSQL 事务—MVCC

概述

PostgreSQL支持了MVCC,所以当执行Delete时,不会也不能彻底删除相关元组。对于Delete操作所涉及的元组,PostgreSQL只是设置其t_xmax来表示元组已经被t_xmax对应的事务删除。但此时,这条元组可能依然对某些查询事务可见,这就是元组不能直接删除的原因。那么接下来就涉及两个问题?

  • 元组何时可以被删除?
  • 元组何时被删除?

关于元组何时被删除,这里直接给出答案:在用户执行Vacuum时。而元组何时可以被删除则是本文重点讨论的内容。其实这个问题的核心思想很简单,元组不能被直接删除,是因为该元组还可能对其他事务可见。那么,只有当元组对所有事务都不可见时,元组才可以被真正删除!在《PostgreSQL 事务—MVCC》中,我们讨论过事务可见性元组可见性,所以我们知道,删除的元组对所有事务都不可见,就意味着元组的t_xmax对所有事务都可见!

这个核心思想,说着比较简单,但是做起来却比较难,下面我们来详细阐述如何判断元组是否可以删除。

元组过期

从前面的描述中,我们知道,一条元组可以被真正删除需要具备两点要素:

  • t_xmax不为0
  • t_xmax被所有活跃事务可见

那么判断一条元组是否可以被删除其实只需要在全局事务链中判断t_xmax的可见性即可。通过《PostgreSQL 事务—MVCC》我们不难看出,判断可见性是一个比较复杂的流程,所以如果按照可见性判断的流程来确定元组是否可以被删除,效率将十分低下。那么有没有什么办法可以提高效率呢?当然有。

在PostgreSQL中,存在一个全局的PGXACT数组,数组中的每一个PGXACT元素代表一个当前的用户进程。PostgreSQL在执行增、删、查、改之前都需要对当前的活跃事务链做一个快照(Snapshot)。然后将快照中最小的事务id存放在PGXACT的xmin成员中。通过《PostgreSQL 事务—MVCC》我们知道,对于当前事务而言,事务id小于xmin的事务对当前事务都可见。那么,如果我们遍历PGXACT数组,获取所有PGXACT->xmin中最小的一个xmin作为globalxmin。事务id小于globalxmin的事务即对当前所有的事务均可见

所以如果我们在每次增、删、查、改之前获取并修改globalxmin,当我们需要判断元组是否可以被删除时,只需要判断元组的t_xmax是否小于globalxmin即可。

获取globalxmin的代码如下:

//procarray.c line 1585
numProcs = arrayP->numProcs;
for (index = 0; index < numProcs; index++)
{
    int			pgprocno = pgprocnos[index];
    volatile PGXACT *pgxact = &allPgXact[pgprocno];
    TransactionId xid;
    
    if (pgxact->vacuumFlags & PROC_IN_LOGICAL_DECODING)
        continue;

    /* Ignore procs running LAZY VACUUM */
    if (pgxact->vacuumFlags & PROC_IN_VACUUM)
        continue;

    /* Update globalxmin to be the smallest valid xmin */
    xid = pgxact->xmin; /* fetch just once */
    if (TransactionIdIsNormal(xid) &&
        NormalTransactionIdPrecedes(xid, globalxmin))
        globalxmin = xid;

    /* Fetch xid just once - see GetNewTransactionId */
    xid = pgxact->xid;

    if (!TransactionIdIsNormal(xid)
        || !NormalTransactionIdPrecedes(xid, xmax))
        continue;

    if (NormalTransactionIdPrecedes(xid, xmin))
        xmin = xid;
    if (pgxact == MyPgXact)
        continue;

    /* Add XID to snapshot. */
    snapshot->xip[count++] = xid;

    if (!suboverflowed)
    {
        if (pgxact->overflowed)
            suboverflowed = true;
        else
        {
            int	nxids = pgxact->nxids;

            if (nxids > 0)
            {
                volatile PGPROC *proc = &allProcs[pgprocno];

                memcpy(snapshot->subxip + subcount,
                       (void *) proc->subxids.xids,
                       nxids * sizeof(TransactionId));
                subcount += nxids;
            }
        }
    }
}

判断元组是否可以被删除的函数为HeapTupleSatisfiesVacuum

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值