PostgreSQL中仅堆元组机制

PostgreSQL与其他DBMS的不同之处在于,在UPDATE操作期间,不会对现有行进行更改,而是制作了行副本,该行副本与原始行有所不同,但列值受更新影响-它们在原始行中很旧并且在副本中已更改。 一方面,这种方法允许您在执行读写请求时避免锁定,另一方面,它需要不断清除没有人会读取的旧版本的字符串。 与该体系结构功能有关,通常会产生一个问题,即如果您需要在数据库中存储诸如最后一次访问数据的时间之类的东西,而该时间原本不会改变,那将会发生什么。 它会对性能产生反应吗? 是否会导致指数的不断调整?


简而言之,是的,“写时复制”将无处可去,但是由于HOT,在许多情况下无法重建索引。


仅堆元组(也称为HOT)是Postgres用于减少更新所需的I / O量的优化。 由于MVCC,Postgres中的更新包括查找更新行,并将该行的新版本插入数据库。 此过程的主要缺点是需要向每个索引重新添加一行。
这需要更多的I / O,因为该行需要重新插入到表中的每个索引中。 由于磁盘上新版本的物理位置与旧版本的物理位置不同,因此需要重新插入。


为了减少UPDATE所需的I / O量,Postgres团队将HOT添加到了Postgres。 HOT背后的想法相对简单。 更新该行时,如果可能,Postgres将在该行的旧副本之后立即放置该行的新副本。 另外,在字符串的旧副本中,会贴上一个特殊标签,以便Postgres知道字符串的新副本紧随旧字符串之后。 因此,不需要更新所有索引。


在通过索引进行扫描时,字符串的新副本将通过该索引,Postgres筛选器将找到该字符串的旧副本。 由于该行的旧副本上有一个特殊标签,因此Postgres将理解该行的新副本位于旧行之后,并会找到并使用新版本。 事实证明,在这种情况下,Postgres的行为就好像所有索引都指向该字符串的新副本一样,并且不需要重新构建它们。


现在,仅当更新中仅包含不可索引的列时,才涉及HOT。 如果索引中至少包含一列参与更新,则无法应用HOT。 在这种情况下,使用HOT存在几个问题。 例如,当需要更新的列索引通过扫描索引并且该行的旧副本属于扫描谓词时,而新副本则不包含在扫描谓词中。 在这种情况下,Postgres将尝试使用索引来快速查找适合查询谓词的所有行,并且对于使用HOT更新的列,它将生成与查询谓词不匹配的行的新副本。 由于此限制(当更新中包含可索引的列时,HOT无法工作),Postgres可以保证,当他尝试查找适合通过该谓词的谓词的行时,如果谓词与该行的旧版本匹配,则该行的新版本也适合他,反之亦然。


当前正在开发一个称为WARM的HOT扩展,该扩展在更新创建索引的列时也可以使用。 WARM的想法是在旧行之后立即放置新行,并为已更改列的索引更新行。 这使所描述的情况大大复杂化,因为现在Postgres需要一种以某种方式确定行是否通过索引过滤器的方法。


PS在原始文章中,描述了HOT机制,但是在这里我们要记住只涉及堆元组的机制,该术语本身具有单独的含义。


仅堆元组只是该行的新版本。 看起来很奇怪,Heap是一个表,并且Heap仅意味着只能通过从旧版本的根(称为根)开始的链找到该行。

Source: https://habr.com/ru/post/zh-CN475642/


All Articles