分享
 
 
 

PostgreSQL数据库学习手册之日常数据库维护工作

王朝mssql·作者佚名  2008-05-18
窄屏简体版  字體: |||超大  

Chapter 8. 日常数据库维护工作

Table of Contents

8.1. 一般性讨论

8.2. 日常清理

8.2.1. 恢复磁盘空间

8.2.2. 更新规划器统计

8.2.3. 避免事务 ID 重叠造成的问题

8.3. 经常重建索引

8.4. 日志文件维护

8.1. 一般性讨论

为了保持所安装的 PostgreSQL 平稳运行, 我们必须做一些日常性的维护工作.我们在这里讨论的这些工作都是 经常重复的事情,可以很容易地使用标准的 Unix 工具,比如 cron 脚本来实现.不过,设置合适的脚本 以及检查它们是否成功执行则是数据库管理员的责任,

一件很明显的维护工作就是经常性地创建数据的备份拷贝. 如果没有最近的备份,那么你就没有从灾难中恢复的机会 (比如磁盘坏了,失火,误删了表等等).可以在 PostgreSQL 里面使用的备份和 恢复机制在 Chapter 9 里面有比较详细的讨论.

其它主要的维护范畴的工作包括周期性的 "vacuuming" (清理)数据库.这个工作我们在 Section 8.2 里讨论.

其它需要周期性注意的东西是日志文件的管理. 我们在 Section 8.4 里讨论了这个问题.

PostgreSQL 和其它数据库产品比较起来 是低维护量的.但是,适当在这些任务上放一些注意将更加能够 确保我们的愉快工作和获取对这个系统富有成效的经验.

8.2. 日常清理

由于以下几个原因,PostgreSQL 的 VACUUM 命令必须周期性地运行∶

1.

恢复那些由已更新的或已删除的行占据的磁盘空间.

2.

更新 PostgreSQL 查询规划器 使用的数据统计信息.

3.

避免因为事务 ID 重叠造成的 老旧数据的丢失.

对上面每个条件进行 VACUUM 操作的频率和范围因 不同的安装而不同.因此,数据库管理员必须理解这些问题并且 开发出合适的维护策略.本节的重点就放在解释这些高级别的问题; 至于命令语法的细节,请参阅 VACUUM 命令手册页.

从 PostgreSQL 7.2 开始, VACUUM 的标准形式可以和普通的数据库操作 (selects, inserts, updates, deletes, 但不包括表大纲的修改). 因此日常的清理也不再象以前的版本那样具有干扰性, 也不再那么特别要求安排在每天的低使用的时间里进行.

8.2.1. 恢复磁盘空间

在正常的 PostgreSQL 操作里, 对一行的UPDATE或DELETE并未立即删除旧的 元组 (行的版本).这个方法对于获取多版本并行控制的好处是必要的 (参阅 PostgreSQL 7.3 用户手册)∶ 如果一条元组仍有可能被其它事务看到,那么你就 不能删除它.但到了最后,不会有任何事务对过期的或者已经删除的元组 感兴趣.而它占据的空间必须为那些新的元组使用而回收, 以避免对磁盘空间增长的无休止的需求.这件事是通过运行 VACUUM 实现的.

很明显,那些经常更新或者删除元组的表需要比那些较少更新的表 清理的更频繁一些.所以,设置一个周期性的 cron 任务清理那些选定的表,而忽略那些已经知道变化比较少的表. 这个方法只是在你拥有大量更新频繁的表和大量很少更新的表的时候 有意义 --- 清理一个小表的额外开销根本不值得担心.

标准形式的 VACUUM 最适合用于维护相当程度的磁盘 用量的稳定状态.标准形式的 VACUUM 找出旧的元组 并且把它们的空间标记为可以在表内再次使用,不过它没有特别努力 地缩小这个表文件并且把它们归还给操作系统. 如果你需要把磁盘空间归还给操作系统,那么你可以使用 VACUUM FULL --- 不过如果释放的磁盘空间又会很快 再次被分配又怎样?如果维护更新频繁的表,那么 中等频率的标准 VACUUM 方法比 很低频率的 VACUUM FULL 更好.

对于大多数节点而言,我们推荐的习惯是在一天中的低使用的时段 安排一次整个数据库的 VACUUM,必要时外加对更新 频繁的表的更经常的清理.(如果你的安装中有多个数据库, 别忘记对每个库进行清理;vacuumdb 脚本可能会帮 你的忙.) 在日常回收空间的清理中,使用简单的 VACUUM, 而不要用 VACUUM FULL.

如果你知道自己刚删除掉一个表中大部分的元组,那么我们建议使用 VACUUM FULL,这样该表的稳定态尺寸可以 因为VACUUM FULL更富侵略性的方法而显著减小.

如果你有一个表,它的内容经常被完全删除,那么可以考虑用 TRUNCATE,而不是后面跟着 VACUUM 的 DELETE.

8.2.2. 更新规划器统计

PostgreSQL 的查询规划器依赖 一些有关表内容的统计信息用以为查询生成好的规划.这些 统计是通过ANALYZE 命令获得的,你可以直接调用 这条命令,也可以把它当做 VACUUM 里的一个可选 步骤来调用.拥有合理准确的统计是非常重要的,否则,选择了 恶劣的规划很可能降低数据库的性能.

和为了回收空间做清理一样,经常更新统计信息也是对更新频繁的 表更有用.不过,即使是更新非常频繁的表,如果它的数据的统计分布 并不经常改变,那么也不需要更新统计信息. 一条简单的拇指定律就是想想表中字段的最大很最小值改变的幅度. 比如,一个包含行更新时间的 timestamp 字段将是 随着行的追加和更新稳定增长最大值的;这样的字段可能需要比那些 包含访问网站的 URL 的字段更频繁一些更新统计信息.那些 URL 字段 可能改变得一样频繁,但是其数值的统计分布的改变相对要缓慢得多.

我们可以在特定的表,甚至是表中特定的字段上运行 ANALYZE, 所以如果你的应用有需求的话,我们是可以对某些信息更新得比其它信息更 频繁的.不过,在实际中,这种做法的有用性是值得怀疑的. 从 PostgreSQL 7.2 开始, ANALYZE 是一项相当快的操作,即时在大表上也很快, 因为它使用了统计学上的随机采样的方法进行行采样, 而不是把每一行都读取进来.因此,每隔一段时间对整个数据库运行 一便这条命令可能更简单.

小技巧: 尽管用 ANALYZE 按字段进行挖掘的方式可能不是 很实用,但你可能还是会发现值得 按字段对 ANALYZE 收集的统计信息的详细级别进行调整. 那些经常在WHERE子句里使用的字段如果有非常不规则的数据分布, 那么就可能需要比其它字段更细致的数据图表.参阅 ALTER TABLE SET STATISTICS.

我们对大多数节点都建议在每天的低使用时段安排一次 数据库范围的 ANALYZE∶这个任务可以有效地 和每天的 VACUUM 组合在一起. 不过,这对那些表统计信息改变相对缓慢的节点可能会过于夸张, 而且少一些的 ANALYZE 也足够了.

8.2.3. 避免事务 ID 重叠造成的问题

PostgreSQL 的 MVCC 事务语意依赖于 比较事务 ID(XID)的数值∶一条带有表当前事务的 XID 更新的插入 XID 的元组是"属于未来的",并且不应 为当前事务可见.但是因为事务 ID 的大小有限(在我们写这些的时候 是 32 位),如果一次安装如果运行的时间很长(大于 4 千兆次事务), 那么它就要受到事务 ID 重叠的折磨∶XID 计数器 回到零位,然后突然间所有以前的事务就变成看上去是在将来的 --- 这意味着它们的输出将变得可见.简而言之,可怕的数据丢失, (实际上数据仍然在那里,但是如果你无法获取数据,这么说也只是 幸灾乐祸.)

在 PostgreSQL 7.2 之前, 防御 XID 重叠的唯一办法就是至少每4千兆事务就重新做一次 initdb.这种做法对高流量的节点而言当然不是令人满意 的做法,所以我们设计了更好的方法.新的方法允许某个安装仍然保持 运行状态,不需要 initdb 或者任何类型的重启. 代价就是下面这样的维护要求∶: 数据库中的每个表都必须在每十亿次事务中至少清理一次 .

从实际角度出发,这个要求不算一个很繁重的要求, 但是因为如果我们没能满足这个要求的后果是全部数据的丢失 (而不仅仅是磁盘空间的浪费或者性能的下降), 我们制作了一些特殊的东西来帮助数据库管理员跟踪自上次 VACUUM 以来的时间.本节剩余的部分给出这些细节.

XID 比较的新方法剥离出两个特殊的 XID,数字 1 很 2 (BootstrapXID 很 FrozenXID). 这两个 XID 总是被认为表任何普通的 XID 旧.普通的 XID (那些大于 2 的) 使用模-231运算进行比较.这就意味着对于 每个普通的 XID,总是有二十亿个 XID 是"更旧"以及 二十亿个 XID"更新";表达这个意思的另外一个方法是 普通的 XID 空间没有终点的环. 因此,一旦一条元组带着特定的普通 XID 创建出来,那么该元组 将在以后的二十亿次事务中表现得是"在过去",而不管我们 说的是哪个普通 XID.如果该元组在超过二十亿次事务之后仍然存在, 那么它就会突然变成在将来的元组.为了避免数据丢失,老的元组必须 在到达二十亿次事务的年龄之前的某个时候赋予 XID FrozenXID. 一旦它被赋予了这个特殊的 XID,那么它们在所有普通事务面前表现为 "在过去",而不管事务 ID 是否重叠,因此这样的元组直到删除 之前都会完好,不管要保存多长时间.这个 XID 的重新赋值是 VACUUM 控制的.

VACUUM 的正常策略是给任何其普通 XID 有超过十亿次已过去事务 元组重新赋值为 FrozenXID.这个策略保留了原来的插入 XID 直到该数值不再令人感兴趣为止(实际上,大多数元组将可能在还没有 "冻结"之前就生存或消亡).在这个策略下,任何表 在 VACUUM 之间的最大的安全间隔是十亿次事务∶如果你等的 时间更长,那么最后就可能就会有一条不够老的元组在重新赋值时 变成比二十亿次事务更老,并因此重叠到了未来 --- 也就是说,你失去它了. (当然,它在另外二十亿次事务之后会重新出现,不过那样也无济于事.)

因为上面的原因,我们需要周期性地运行 VACUUM, 所以很难有哪个表会到十亿次事务还没有清理过.但是,为了 帮助管理员确保满足了这个要求,VACUUM 在系统表 pg_database 里存储了事务 ID 统计.尤其是 一个数据库的 pg_database 行中的 datfrozenxid 字段在任何数据库范围的清理操作(也就是没有声明任何表的 VACUUM)之后将会被更新.这个字段里存储的数值是 该 VACUUM 命令使用的冻结中止的 XID. 系统保证在该数据库中所有比这个中止 XID 老的普通 XID 都 被 FrozenXID 代替.检查这个信息的一个便利的方法是 执行下面的查询

SELECT datname, age(datfrozenxid) FROM pg_database;

age 字段用于测量从中止 XID 到当前事务的 XID 的数目.

使用了这种标准的冻结策略,对一个刚清理过的数据库而言, age 字段将从十亿处开始.当age到达二十亿次的 时候,数据库必须再次清理以避免事务标识重叠造成的问题. 我们建议的策略是至少每半个十亿次(500 百万)事务清理一次数据库, 这样就可以保证足够的安全边界范围.为了帮助满足这条规则, 如果有任何 pg_database 记录显示出超过 15亿次事务的 age,那么每次数据库范围的 VACUUM 都会自动发出一条警告,比如∶

play=# vacuum;

WARNING: Some databases have not been vacuumed in 1613770184 transactions.

Better vacuum them within 533713463 transactions,

or you may have a wraparound failure.

VACUUM

带着 FREEZE 选项的 VACUUM 使用了更 大胆的冻结策略∶如果元组已经老得被所有打开的事务看做是良好的, 那么就都冻结.特别是如果在一个空闲的数据库上运行 VACUUM FREEZE,那么就保证该数据库中所有 的元组都被冻结.因此,只要该数据库没有其它的变化,那么它就不需要 后续的清理以避免事务 ID 重叠问题. 这个技巧被 initdb 用于准备 template0 数据库.我们也应该用这个方法对所有在 pg_database 表里标记着 datallowconn = false的数据库 进行初始化,因为我们还没有任何便利的方法清理一个你无法联接的 数据库.请注意,VACUUM 将忽略那些 pg_database 记录里有 datallowconn = false, 的那些有关未清理数据库的自动警告信息. 以避免给出关于这些数据库的虚假的警告信息; 因此,确保这样的数据库的正常冻结是你的责任.

8.3. 经常重建索引

PostgreSQL 在某些情况下不能复用 B-tree 索引页面。问题是这样的如果索引行被删除,那么那些索引页面只能被那些 有着相似数值的行所利用。比如,如果一个索引行被删除,而新插入或者更新 的行的数值高得多,那么新行就不能使用已经删除的行用过的索引空间。 这样的新行就必须放在一个新的索引页面里。这个时候,索引使用的磁盘空间 就会不确定地增长,即使经常运行 VACUUM 也会这样。

为了解决这个问题,你可以周期性使用 REINDEX 命令 抛弃已删除行使用地磁盘空间。在 contrib/reindexdb 里面还有 一个贡献包,可以对整个数据库进行重建索引的工作。

8.4. 日志文件维护

把数据库服务器的日志输出保存在一个地方是个好主意, 而不是仅仅把它们放到 /dev/null 里. 在碰到危险的问题的时候,日志输出是非常宝贵的.不过, 日志输出可能很庞大(特别是在比较高的调试级别上), 而且你不会无休止地保存它们.你需要"旋转"日志文件, 这样生成新的日志文件并且经常抛弃老的.

如果你简单地把 postmaster 的stderr定向到一个文件中, 那么截断日志文件的唯一的方法是停止并重起 postmaster. 这样做对于开发环境可能是可以的,但是你肯定不想在生产环境上这么干.

最简单的生产级的管理日志输出的方法就是把它们发送给 syslog,让 syslog 处理文件旋转. 要利用这个工具,确保 PostgreSQL 制作的时候打开了 --enable-syslog 选项并且把 postgresql.conf 里的 syslog 设置为 2 (只记录 syslog 日志).然后在你想强迫 syslog 守护进程 开始写入一个新日志文件的时候, 你就可以发送一个 SIGHUP 信号给它.

不过,在很多系统上,syslog 不是非常可靠,特别是在大型日志信息的情况下; 它可能在你最需要那些信息的时候截断或者丢弃它们. 你可能会觉得把 postmaster 的stderr 输出给某些 日志旋转脚本会更有用些.如果你用 pg_ctl 启动 postmaster,那么 postmaster 发热stderr已经重定向到 stdout,因此 你只需要一个管道命令∶

pg_ctl start | logrotate

PostgreSQL 版本并未包含合适的日志旋转程序, 但是在网上有许多不错的,比如 Apache 就带着一个.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有