PostgreSQL维护——解决索引膨胀和数据死行

server/2024/9/21 8:56:28/

注意: 本文内容于 2024-09-16 00:40:33 创建,可能不会在此平台上进行更新。如果您希望查看最新版本或更多相关内容,请访问原文地址:PostgreSQL维护——解决索引膨胀和数据死行。感谢您的关注与支持!

我有一张表,为了保障查询的快速响应,我是在必要的字段上建立了索引。该表的数量基数不变,只是每分钟会更新过来一批数据,如此运行了一年之久,目前即使走索引查询,依旧特别慢。

排查主要是由两个现象导致的。

  1. 索引膨胀
  2. 数据死行

这两个现象是如何出现的呢?频繁的进行insert/update/delete就会出现。

一、复现

下面来简单复现一下。

复现步骤

  1. 创建新表、关闭自动vacuum。vacuum如果开启,就会导致死行问题不复现。
  2. 录入样本数据、并创建索引,默认采用btree。我设置的样本数据为2000行。
  3. 执行insert/update/delete操作,执行10000次,并保持最后的数据总量仍然为2000条。
    • insert && delete:删除的数据作为新数据插入
    • update:更新其他数据字段
  4. 分别比较执行前与执行后的索引总量、死行数量。

以上复现步骤,我已经编写了一套脚本。开箱即用。

脚本地址

取其中一套运行结果,如下

大小/操作阶段insert && delete 前insert && delete 后update 前update 后
索引144KB832KB144KB976KB
数据136KB640KB136KB384KB
死行0行9754行0行9850行

2000条数据在频繁进行insert/delete/update之后,就会导致索引异常膨胀,是原数据大小的几倍之多。即使数据的总数未变,占用的数据空间仍然变大,因为数据死行导致的。

这两个问题,都会直接或者间接影响到数据库的查询速率。如果

二、临时解决方案

数据死行与索引膨胀,根源在于PostgreSQL的MVCC(Multi-Version Concurrency Control),有兴趣可以查阅官方文档。

2.1 数据死行

在 PostgreSQL 中,UPDATE 操作不会直接修改原有行,而是生成一条新的行记录,同时将原有行标记为“死行”,但并不会立即删除它。类似于 UPDATE,DELETE 操作不会立即删除数据行,而是将其标记为“死行”,并等待后续的 VACUUM 操作来真正回收空间。因此,频繁的 DELETE 操作也会导致死行积累。

临时解决方式:vaccum

VACUUM 是 PostgreSQL 中的垃圾收集机制,用于回收那些不再使用的“死”行空间,但不会释放表文件大小。它会标记那些不再使用的行,可以被新数据覆盖,操作过程中不会锁表。

-- vacuum整个库
vacuum;
-- vacuum单个表
vacuum 表名;

其中涉及到的查询死行的SQL如下

select n_dead_tup from pg_stat_user_tables where n_dead_tup>0 and relname='test_data';

2.2 索引膨胀

在 PostgreSQL 中,每次执行 UPDATE 或 DELETE 操作时,并不会直接修改或删除原有的记录。

相反,旧的版本(元组)会被标记为“死行”,而新的数据将作为一个新的行版本插入表中。

对于索引字段,原有的索引条目不会立即被删除,而是新建一个指向新数据的索引条目。因此,频繁的 UPDATE 和 DELETE 会导致索引包含大量的过时条目,引发索引膨胀、查询效率降低。

临时解决方式:重建索引

最简单的方式是先删再增

比较方便的方式是reindex,但是该方式会在重建的过程中锁表。

reindex table 表名;
reindex index 索引名;

自从PostgreSQL12开始,reindex支持并行重建索引,不会锁表,但比直接reindex要慢。

reindex table concurrently 表名;
reindex index concurrently 索引名;

其中涉及到的一些查询索引大小的SQL如下

-- 查询表内总数据大小
select pg_table_size('test_data'),pg_size_pretty(pg_table_size('test_data'));-- 查询表内总索引大小
select pg_indexes_size('test_data'),pg_size_pretty(pg_indexes_size('test_data'));-- 查询表的总大小,包含数据和索引
select pg_total_relation_size('test_data'),pg_size_pretty(pg_total_relation_size('test_data'));

三、设计层面规避该问题

单表数据量大,创建索引来加速查询效率,同时又要进行增删改数据。使用单表的做法在短时间内,是个轻量快速的好做法,适合敏捷式开发。但是长时间来看,还需要经常的人工维护,或者配置数据库的定时清理机制(又会存在锁表等问题),这并不好。

在大型项目上,以上做法就不太适合了。因此在设计上,可以做读写分离,实现一劳永逸。

  • 专门的写表,不创建索引,用来快速增删改。

  • 专门的读表,创建索引,用来快速查询。读表数据来源于写表,这之间需要设计一套适应当前需求的同步机制。

这套同步机制,根据我当前的需求,主要有两种同步方式。

  1. 批量增量同步:程序上定期将写表中增量的数据,一次性批量更新到读表。周期根据需求设定。
  2. 全量同步:读表增量同步也会存在膨胀的问题,因此可以定期的将备份一张新的全量读表,替换掉原来的读表。

在PostgreSQL中,如果数据量不是特别大,读表不需要单独建表去维护,直接使用物理视图即可,根据周期定时刷新。

物理视图跟逻辑视图的区别

逻辑视图需要在查询视图时,根据视图逻辑实时查询,与原数据表相比不存在数据差异性问题。

物理视图相当于创建了一张临时表并存储到了磁盘,不会自动更新,需要人工维护。

举例物理视图用法

-- 重建物理视图
drop materialized view if exists view_name;
create materialized view view_name AS
select * from test_data;
-- 锁表更新物理视图
refresh materialized view view_name;
-- 并行更新物理视图,首先需要物理视图有唯一键
create unique index unique_id_index ON view_name (id);
refresh materialized view concurrently view_name;

http://www.ppmy.cn/server/119741.html

相关文章

基于python+django+vue的家居全屋定制系统

作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于协同过滤pythondjangovue…

solidity-21-call_contract

调用其他合约 练笔时刻,首先创建一个合约用于被其他合约调用 // SPDX-License-Identifier: MIT pragma solidity ^0.8.21;contract othercontract{// 定义一个只有自己能访问的参数uint256 private _x 0;event log(uint amount,uint gas);function getbalance() …

linux命令行快捷键

第一章 linux之帮助命令 第二章 linux命令行快捷键 文章目录 linux命令行快捷键 linux命令行快捷键 Tab 命令补全或文件补全Ctrlu 删除或剪切光标之前的命令Ctrla 将光标移动到命令行开头Ctrle 将光标移动到命令行结尾ctrlc 终止当前命令ctrll 清屏ctrly 粘贴ctrlu的内容 参考…

使用注意力机制可以让你的模型更加灵活,但是需要额外的计算资源。rnn lstm bilstm attension

确实,使用注意力机制可以使模型更加灵活,但也确实需要额外的计算资源。注意力机制允许模型在处理序列数据时,能够动态地关注不同位置的重要性,从而更好地捕捉长依赖关系。下面是一个简单的注意力机制实现示例,可以帮助…

基于VUE的学生信息系统的设计与实现,包含学籍,成绩,课程选择选课,成绩分析统计百度图表echarts等功能

学生信息系统是一种用于管理学校学生信息的电子化系统,可以方便学校管理者和教师对学生的信息进行录入、查询和统计等操作,提高学校管理效率。本文将介绍学生信息系统的设计与实现。 首先,学生信息系统应该具备以下功能: 学生信息…

904.水果成篮

目录 题目介绍解题方法 题目介绍 解题方法 题目翻译成人话就是 :找包含两种元素的最长子串,返回其长度,和2958题的区别是:本题是找种类最多为2,上题是单个种类个数最多为k。 法一: class Solution {publ…

JavaSE--集合总览02:单列集合Collection的体系之一:List

Collection体系的特点 分为 list 和set集合,这篇文章主要讲述List,下篇讲述Set。 简单认识单列集合collection集合的特点 : list集合的特点: 有序 可重复 有索引 set集合的特点:无序 不重复 无索引 其中LinkedHashSet有序 TreeS…

大数据处理技术:MapReduce综合实训

目录 1 实验名称 2 实验目的 3 实验内容 4 实验原理 5 实验过程或源代码 5.1 WordCount词频统计 5.2 HDFS文件读写 5.3 倒排索引 5.4 网页排序——PageRank算法 6 实验结果 6.1 WordCount词频统计 6.2 HDFS文件读写 6.3 倒排索引 6.4 网页排序——PageRank算法 1…