过多的索引会降低数据库性能,包括写入和读取速度减慢、浪费磁盘空间、增加缓存压力和WAL记录。定期监控和重建索引是必要的维护工作,建议删除未使用和冗余的索引,以保持索引集精简。
在Postgres中,不同的plan_cache_mode设置对分区表的锁行为影响显著。默认模式下,执行第六次时会出现锁爆炸,需锁定所有关系。强制使用通用计划时,首次执行锁定52个关系,后续执行锁定所有分区。强制使用自定义计划则每次执行仅需8个锁。选择应根据工作负载和锁竞争情况,未来可能有优化。
在#PostgresMarathon 2-009中,我们分析了锁管理器在处理准备语句和分区表时的表现。第六次调用时,锁的数量从8个激增至52个,原因是规划阶段未能进行分区修剪。尽管运行时修剪移除了11个分区,但仍锁定了所有12个分区。
在#PostgresMarathon 2-008中,预处理语句显著减少了LWLock:LockManager的争用。通过从规划器锁切换到执行器锁,锁的数量从6降至1。测试分区表时,执行6时锁数量从8增至52,但执行7后,使用缓存的通用计划,锁数量显著减少。
Postgres在执行简单SELECT时,前五次使用自定义计划,锁定表及所有索引。第六次切换到通用计划,但仍锁定所有索引。第七次开始仅锁定表。这是由于规划器锁和执行器锁的机制不同所致。
文章讨论了pg_blocking_pids()函数对PostgreSQL数据库性能的观察者效应。频繁调用该函数可能导致锁管理器争用,影响查询延迟约10%。尽管影响不大,但在高负载情况下应谨慎使用。
max_locks_per_transaction参数限制每个事务可锁定的对象数量,默认值为64。它影响共享锁表的大小,实际可锁定对象数量可能超出预期,理解这一点有助于避免“共享内存不足”的错误。不同Postgres版本在相同设置下表现不同,锁表动态增长,具体机制尚不清晰。
在2023-2024年,PostgresAI的客户在大机器上遇到LWLock:LockManager争用问题。PG18发布后,Denis Morozov在16个vCPU的虚拟机上成功重现了该问题。调整max_locks_per_transaction后发现其对规划时间有影响。计划对PG17进行基准测试,并研究小型机器是否会出现类似问题。
Postgres 18中,快速路径锁的存储方式发生变化,支持根据每个事务的最大锁数动态调整锁的数量,从而缓解多核系统中的锁竞争问题。通过使用私有数组存储弱锁,减少了共享内存的争用,提升了性能。
锁管理器负责管理重型锁,事务结束时释放。SELECT操作会锁定表及其索引。Postgres 8.2之前,所有锁信息存储在一个哈希表中,导致竞争。为缓解此问题,哈希表被分为16个分区。2011年引入快速路径锁,减少竞争并提升性能。Postgres 18进一步优化以应对分区带来的挑战。
Let's talk about relation-level locks and various confusions, surprises and what is worth to remember in practice. The key page in Postgres docs describing relation-level locks is here:...
轻量级锁(LWLocks)用于协调共享内存的快速访问,适合读写操作。重型锁用于管理数据库等高层资源的并发访问,直到事务结束。锁管理器负责重型锁的管理,用户可以监控锁的获取情况。锁争用可能由资源不足或配置不当引起。
完成下面两步后,将自动完成登录并继续当前操作。