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

PostgreSQL数据库vacuum在什么情况下会Truncate the last page if possible

SmallDB 2024-11-01
12

源码位置

 vim ./src/backend/access/heap/vacuumlazy.c

清理条件

/*
 * Space/time tradeoff parameters: do these need to be user-tunable?
 *
 * To consider truncating the relation, we want there to be at least
 * REL_TRUNCATE_MINIMUM or (relsize / REL_TRUNCATE_FRACTION) (whichever
 * is less) potentially-freeable pages.
 */

#define REL_TRUNCATE_MINIMUM    1000
#define REL_TRUNCATE_FRACTION   16

/*
 * Timing parameters for truncate locking heuristics.
 *
 * These were not exposed as user tunable GUC values because it didn't seem
 * that the potential for improvement was great enough to merit the cost of
 * supporting them.
 */

#define VACUUM_TRUNCATE_LOCK_CHECK_INTERVAL             20      /* ms */
#define VACUUM_TRUNCATE_LOCK_WAIT_INTERVAL              50      /* ms */
#define VACUUM_TRUNCATE_LOCK_TIMEOUT                    5000    /* ms */

/*
 * Threshold that controls whether we bypass index vacuuming and heap
 * vacuuming as an optimization
 */

#define BYPASS_THRESHOLD_PAGES  0.02    /* i.e. 2% of rel_pages */

清理实际动作

自己的理解

  • • 末尾空page数大于1000 (REL_TRUNCATE_MINIMUM)

  • • 末尾空page数大于总page数的1/16(REL_TRUNCATE_FRACTION)

  • • old_snapshot_threshold<0 不能清理或者使用这个特性 ```

9.6引入了old_snapshot_threshold参数,表示快照超过多长时间后,vacuum就可以删除其保留的dead tuple。单位是分钟,默认为-1,表示禁止该特性。这样可以避免表膨胀,但是长事务读取被删除tuple时会报错,snapshot too old


```c
/*
 * should_attempt_truncation - should we attempt to truncate the heap?
 *
 * Don't even think about it unless we have a shot at releasing a goodly
 * number of pages.  Otherwise, the time taken isn't worth it.
 *
 * Also don't attempt it if wraparound failsafe is in effect.  It's hard to
 * predict how long lazy_truncate_heap will take.  Don't take any chances.
 * There is very little chance of truncation working out when the failsafe is
 * in effect in any case.  lazy_scan_prune makes the optimistic assumption
 * that any LP_DEAD items it encounters will always be LP_UNUSED by the time
 * we're called.
 *
 * Also don't attempt it if we are doing early pruning/vacuuming, because a
 * scan which cannot find a truncated heap page cannot determine that the
 * snapshot is too old to read that page.
 *
 * This is split out so that we can test whether truncation is going to be
 * called for before we actually do it.  If you change the logic here, be
 * careful to depend only on fields that lazy_scan_heap updates on-the-fly.
 */
static bool
should_attempt_truncation(LVRelState *vacrel)
{
        BlockNumber possibly_freeable;

        if (!vacrel->do_rel_truncate || vacrel->failsafe_active)
                return false;

        possibly_freeable = vacrel->rel_pages - vacrel->nonempty_pages;
        if (possibly_freeable > 0 &&
                (possibly_freeable >= REL_TRUNCATE_MINIMUM ||
                 possibly_freeable >= vacrel->rel_pages / REL_TRUNCATE_FRACTION) &&
                old_snapshot_threshold < 0)
                return true;
        else
                return false;
}

实际执行的位置

/*
 * Optionally truncate the relation.
 */

if (should_attempt_truncation(vacrel))
{
        /*
         * Update error traceback information.  This is the last phase during
         * which we add context information to errors, so we don't need to
         * revert to the previous phase.
         */

        update_vacuum_error_info(vacrel, NULL, VACUUM_ERRCB_PHASE_TRUNCATE,
                                                         vacrel->nonempty_pages,
                                                         InvalidOffsetNumber);
        lazy_truncate_heap(vacrel);
}

总结

  • • 看到里面的逻辑好的选项控制条件AccessExclusiveLock拿到8级锁,拿不到报错

  • • pg_usleep 沉睡时间

源码参考 postgres/src/backend/access/heap/vacuumlazy.c at master · postgres/postgres


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

评论