欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

PostgreSQL HOT與PHOT有哪些區(qū)別

 更新時(shí)間:2022年09月19日 10:34:26   作者:foucus、  
這篇文章主要介紹了PostgreSQL8.3版本開始就引入的HOT機(jī)制與PHOT使用區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

1、HOT概述

PostgreSQL中,由于其多版本的特性,當(dāng)我們進(jìn)行數(shù)據(jù)更新時(shí),實(shí)際上并不是直接修改元數(shù)據(jù),而是通過新插入一行數(shù)據(jù)來進(jìn)行間接的更新。而當(dāng)表上存在索引時(shí),由于新插入了數(shù)據(jù),那么索引必然也需要同步進(jìn)行更新,這在索引較多的情況下,對(duì)于更新的性能影響必然很大。

為了解決這一問題,pg從8.3版本開始就引入了HOT(Heap Only Tuple)機(jī)制。其原理大致為,當(dāng)更新的不是索引字段時(shí),我們通過將舊元組指向新元組,而原先的索引不變,仍然指向舊元組,但是我們可以通過舊元組作為間接去訪問到新的元組,這樣就不用再去更新索引了。

2、HOT實(shí)現(xiàn)技術(shù)細(xì)節(jié)

要使用HOT進(jìn)行更新,需要滿足兩個(gè)前提:

  • 新的元組和舊元組必須在同一個(gè)page中;
  • 索引字段不能進(jìn)行更新。

當(dāng)我們進(jìn)行HOT更新時(shí),首先是分別設(shè)置舊元組的t_informask2標(biāo)志位為HEAP_HOT_UPDATED和新元組為HEAP_ONLY_TUPLE。

更新如下圖所示:

我們更新tuple1為tuple2,分別設(shè)置這兩行元組的t_informask2標(biāo)志位,然后tuple1的ctid指向tuple2,而tuple2指向自己。

但是這樣存在一個(gè)明顯的問題,我們都知道pg會(huì)定期進(jìn)行vacuum清理那些死元組,那么我們這里如果通過tuple1去訪問tuple2的話,tuple1這個(gè)死元組被清理了又該怎么辦呢?

所以pg會(huì)在合適的時(shí)機(jī)進(jìn)行行指針的重定向,將舊元組的行指針指向新元組的行指針,這一過程稱為修剪。于是在修剪之后,我們通過HOT機(jī)制訪問數(shù)據(jù)便成了這樣:

1、通過索引元組找到舊元組的行指針1;

2、通過重定向的行指針1找到行指針2;

3、通過行指針2找到新元組tuple2。

這樣即使舊元組tuple1被清理掉也沒有影響了。

HOT對(duì)應(yīng)的wal日志實(shí)現(xiàn):

對(duì)于HOT的update操作,其wal日志中記錄的信息主要是由xl_heap_update結(jié)構(gòu)存儲(chǔ)。

如果新的元組存儲(chǔ)在 block_id 為 0 的塊上,如果不是 XLOG_HEAP_HOT_UPDATE,那么舊的元組將會(huì)存儲(chǔ)在 block_id 為 1 的塊上。反之如果block_id 為 1 的塊沒有被使用,那么則認(rèn)為是 XLOG_HEAP_HOT_UPDATE。

3、何時(shí)進(jìn)行修剪

前面我們提到了,舊行的行指針會(huì)重定向到新行的行指針,這一過程稱之為修剪。那么什么時(shí)候會(huì)發(fā)生修剪呢?

一般來說,當(dāng)我們執(zhí)行select、update、insert、delete這些命令時(shí)均有可能觸發(fā)修剪,其觸發(fā)機(jī)制大致有兩種情況:

  • 上一次進(jìn)行update時(shí)無法在本page找到足夠的空間;
  • 當(dāng)前page上剩余空間小于fill-factor的值,最多小于10%

除此之外,當(dāng)進(jìn)行修剪時(shí),還會(huì)選擇合適的時(shí)機(jī)進(jìn)行死元組的清理,這一操作稱為碎片整理。碎片整理發(fā)生在當(dāng)我們對(duì)元組進(jìn)行檢索時(shí)發(fā)現(xiàn)空閑空間少于10%時(shí),和修剪不同的是,碎片整理不會(huì)發(fā)生在insert時(shí),因?yàn)樵摬僮鞑⒉粫?huì)檢索行。

相較于普通的vacuum操作,碎片清理并不涉及索引元組的清理,開銷相對(duì)于常規(guī)的清理要小很多,是通過PageRepairFragmentation函數(shù)來實(shí)現(xiàn)的。

這也是為什么HOT要求新舊元組需要在同一個(gè)page中,雖然從理論上來說我們可以將行指針的鏈表指向不同page,但是這樣我們便不能使用page-local的操作來進(jìn)行碎片清理了。

4、HOT的不足

前面我們提到了HOT的前提條件之一就是:更新的列不能是索引列。需要注意,當(dāng)更新的列是索引列時(shí)并不僅僅是會(huì)修改該列上的索引,整張表上所有的索引均會(huì)被修改。

例子:

創(chuàng)建測(cè)試表:

bill=# create table a(id int, c1 int, c2 int, c3 int);
CREATE TABLE
bill=# insert into a select generate_series(1,10), random()*100, random()*100, random()*100;
INSERT 0 10
bill=# create index idx_a_1 on a (id);
CREATE INDEX
bill=# create index idx_a_2 on a (c1);
CREATE INDEX
bill=# create index idx_a_3 on a (c2);
CREATE INDEX

觀察索引頁內(nèi)容:

bill=# SELECT * FROM bt_page_items('idx_a_1',1);
 itemoffset |  ctid  | itemlen | nulls | vars |          data           | dead |  htid  | tids
------------+--------+---------+-------+------+-------------------------+------+--------+------
          1 | (0,1)  |      16 | f     | f    | 01 00 00 00 00 00 00 00 | f    | (0,1)  |
          2 | (0,2)  |      16 | f     | f    | 02 00 00 00 00 00 00 00 | f    | (0,2)  |
          3 | (0,3)  |      16 | f     | f    | 03 00 00 00 00 00 00 00 | f    | (0,3)  |
          4 | (0,4)  |      16 | f     | f    | 04 00 00 00 00 00 00 00 | f    | (0,4)  |
          5 | (0,5)  |      16 | f     | f    | 05 00 00 00 00 00 00 00 | f    | (0,5)  |
          6 | (0,6)  |      16 | f     | f    | 06 00 00 00 00 00 00 00 | f    | (0,6)  |
          7 | (0,7)  |      16 | f     | f    | 07 00 00 00 00 00 00 00 | f    | (0,7)  |
          8 | (0,8)  |      16 | f     | f    | 08 00 00 00 00 00 00 00 | f    | (0,8)  |
          9 | (0,9)  |      16 | f     | f    | 09 00 00 00 00 00 00 00 | f    | (0,9)  |
         10 | (0,10) |      16 | f     | f    | 0a 00 00 00 00 00 00 00 | f    | (0,10) |
(10 rows)
bill=# SELECT * FROM bt_page_items('idx_a_2',1);
 itemoffset |   ctid    | itemlen | nulls | vars |          data           | dead |  htid  |       tids
------------+-----------+---------+-------+------+-------------------------+------+--------+-------------------
          1 | (0,5)     |      16 | f     | f    | 00 00 00 00 00 00 00 00 | f    | (0,5)  |
          2 | (0,4)     |      16 | f     | f    | 05 00 00 00 00 00 00 00 | f    | (0,4)  |
          3 | (0,8)     |      16 | f     | f    | 0e 00 00 00 00 00 00 00 | f    | (0,8)  |
          4 | (0,9)     |      16 | f     | f    | 25 00 00 00 00 00 00 00 | f    | (0,9)  |
          5 | (16,8194) |      32 | f     | f    | 30 00 00 00 00 00 00 00 | f    | (0,1)  | {"(0,1)","(0,3)"}
          6 | (0,10)    |      16 | f     | f    | 58 00 00 00 00 00 00 00 | f    | (0,10) |
          7 | (0,6)     |      16 | f     | f    | 60 00 00 00 00 00 00 00 | f    | (0,6)  |
          8 | (0,7)     |      16 | f     | f    | 62 00 00 00 00 00 00 00 | f    | (0,7)  |
          9 | (0,2)     |      16 | f     | f    | 63 00 00 00 00 00 00 00 | f    | (0,2)  |
(9 rows)
bill=# SELECT * FROM bt_page_items('idx_a_3',1);
 itemoffset |  ctid  | itemlen | nulls | vars |          data           | dead |  htid  | tids
------------+--------+---------+-------+------+-------------------------+------+--------+------
          1 | (0,6)  |      16 | f     | f    | 03 00 00 00 00 00 00 00 | f    | (0,6)  |
          2 | (0,3)  |      16 | f     | f    | 12 00 00 00 00 00 00 00 | f    | (0,3)  |
          3 | (0,5)  |      16 | f     | f    | 15 00 00 00 00 00 00 00 | f    | (0,5)  |
          4 | (0,9)  |      16 | f     | f    | 1a 00 00 00 00 00 00 00 | f    | (0,9)  |
          5 | (0,4)  |      16 | f     | f    | 33 00 00 00 00 00 00 00 | f    | (0,4)  |
          6 | (0,7)  |      16 | f     | f    | 3d 00 00 00 00 00 00 00 | f    | (0,7)  |
          7 | (0,10) |      16 | f     | f    | 4e 00 00 00 00 00 00 00 | f    | (0,10) |
          8 | (0,1)  |      16 | f     | f    | 4f 00 00 00 00 00 00 00 | f    | (0,1)  |
          9 | (0,2)  |      16 | f     | f    | 5c 00 00 00 00 00 00 00 | f    | (0,2)  |
         10 | (0,8)  |      16 | f     | f    | 5d 00 00 00 00 00 00 00 | f    | (0,8)  |
(10 rows)

更新索引列c2:

bill=# update a set c2=c2+1 where id=1 returning ctid,*;
  ctid  | id | c1 | c2 | c3
--------+----+----+----+----
 (0,11) |  1 | 19 | 66 | 86
(1 row)

UPDATE 1

再觀察索引內(nèi)容:

可以看到3個(gè)索引的索引頁均發(fā)生了變化。

bill=# SELECT * FROM bt_page_items('idx_a_1',1);
 itemoffset |  ctid  | itemlen | nulls | vars |          data           | dead |  htid  | tids
------------+--------+---------+-------+------+-------------------------+------+--------+------
          1 | (0,1)  |      16 | f     | f    | 01 00 00 00 00 00 00 00 | f    | (0,1)  |
          2 | (0,11) |      16 | f     | f    | 01 00 00 00 00 00 00 00 | f    | (0,11) |
          3 | (0,2)  |      16 | f     | f    | 02 00 00 00 00 00 00 00 | f    | (0,2)  |
          4 | (0,3)  |      16 | f     | f    | 03 00 00 00 00 00 00 00 | f    | (0,3)  |
          5 | (0,4)  |      16 | f     | f    | 04 00 00 00 00 00 00 00 | f    | (0,4)  |
          6 | (0,5)  |      16 | f     | f    | 05 00 00 00 00 00 00 00 | f    | (0,5)  |
          7 | (0,6)  |      16 | f     | f    | 06 00 00 00 00 00 00 00 | f    | (0,6)  |
          8 | (0,7)  |      16 | f     | f    | 07 00 00 00 00 00 00 00 | f    | (0,7)  |
          9 | (0,8)  |      16 | f     | f    | 08 00 00 00 00 00 00 00 | f    | (0,8)  |
         10 | (0,9)  |      16 | f     | f    | 09 00 00 00 00 00 00 00 | f    | (0,9)  |
         11 | (0,10) |      16 | f     | f    | 0a 00 00 00 00 00 00 00 | f    | (0,10) |
(11 rows)
bill=# SELECT * FROM bt_page_items('idx_a_2',1);
 itemoffset |  ctid  | itemlen | nulls | vars |          data           | dead |  htid  | tids
------------+--------+---------+-------+------+-------------------------+------+--------+------
          1 | (0,6)  |      16 | f     | f    | 04 00 00 00 00 00 00 00 | f    | (0,6)  |
          2 | (0,9)  |      16 | f     | f    | 0b 00 00 00 00 00 00 00 | f    | (0,9)  |
          3 | (0,1)  |      16 | f     | f    | 13 00 00 00 00 00 00 00 | f    | (0,1)  |
          4 | (0,11) |      16 | f     | f    | 13 00 00 00 00 00 00 00 | f    | (0,11) |
          5 | (0,2)  |      16 | f     | f    | 19 00 00 00 00 00 00 00 | f    | (0,2)  |
          6 | (0,5)  |      16 | f     | f    | 1d 00 00 00 00 00 00 00 | f    | (0,5)  |
          7 | (0,8)  |      16 | f     | f    | 1e 00 00 00 00 00 00 00 | f    | (0,8)  |
          8 | (0,4)  |      16 | f     | f    | 21 00 00 00 00 00 00 00 | f    | (0,4)  |
          9 | (0,3)  |      16 | f     | f    | 28 00 00 00 00 00 00 00 | f    | (0,3)  |
         10 | (0,10) |      16 | f     | f    | 3a 00 00 00 00 00 00 00 | f    | (0,10) |
         11 | (0,7)  |      16 | f     | f    | 4d 00 00 00 00 00 00 00 | f    | (0,7)  |
(11 rows)
bill=# SELECT * FROM bt_page_items('idx_a_3',1);
 itemoffset |  ctid  | itemlen | nulls | vars |          data           | dead |  htid  | tids
------------+--------+---------+-------+------+-------------------------+------+--------+------
          1 | (0,2)  |      16 | f     | f    | 17 00 00 00 00 00 00 00 | f    | (0,2)  |
          2 | (0,7)  |      16 | f     | f    | 18 00 00 00 00 00 00 00 | f    | (0,7)  |
          3 | (0,5)  |      16 | f     | f    | 33 00 00 00 00 00 00 00 | f    | (0,5)  |
          4 | (0,6)  |      16 | f     | f    | 37 00 00 00 00 00 00 00 | f    | (0,6)  |
          5 | (0,4)  |      16 | f     | f    | 38 00 00 00 00 00 00 00 | f    | (0,4)  |
          6 | (0,1)  |      16 | f     | f    | 41 00 00 00 00 00 00 00 | f    | (0,1)  |
          7 | (0,11) |      16 | f     | f    | 42 00 00 00 00 00 00 00 | f    | (0,11) |
          8 | (0,9)  |      16 | f     | f    | 4d 00 00 00 00 00 00 00 | f    | (0,9)  |
          9 | (0,8)  |      16 | f     | f    | 58 00 00 00 00 00 00 00 | f    | (0,8)  |
         10 | (0,3)  |      16 | f     | f    | 62 00 00 00 00 00 00 00 | f    | (0,3)  |
         11 | (0,10) |      16 | f     | f    | 63 00 00 00 00 00 00 00 | f    | (0,10) |
(11 rows)

這也意味著當(dāng)我們無法使用HOT更新時(shí),每更新一條數(shù)據(jù)都會(huì)更新所有的索引,那么這個(gè)對(duì)性能的影響可想而知。而我們簡單想想其實(shí)并沒有這個(gè)必要,因?yàn)閷?duì)于沒有被更新的索引列而言,只是ctid發(fā)生了變化,其索引列指向的值并沒有變化。那么有沒有辦法讓我們更新索引列時(shí)只修改該索引列的索引呢?PHOT應(yīng)運(yùn)而生。

5、PHOT概述

PHOT(Partial Heap Only Tuples),正如我們前面所說,PHOT是為了解決HOT更新索引列時(shí)會(huì)修改索引列的弊端。目前,PG中還不支持該功能,不過社區(qū)中已經(jīng)有相關(guān)的討論了,預(yù)計(jì)可能會(huì)在PG15中和大家見面。

PHOT的設(shè)計(jì)思路主要是:通過在t_infomask2標(biāo)志位新加入兩種類型HEAP_HOT_UPDATED 和HEAP_ONLY_TUPLE用來表示PHOT更新,類似于HOT。當(dāng)我們對(duì)索引列進(jìn)行修改時(shí),通過一個(gè)PHOT的bitmap位圖來記錄哪些索引列被更新了,然后,當(dāng)我們對(duì)索引列修改時(shí),只需要修改這個(gè)bitmap位圖中的列即可。

#define HEAP_HOT_UPDATED		0x4000	/* tuple was HOT-updated */
#define HEAP_ONLY_TUPLE			0x8000	/* this is heap-only tuple */

6、PHOT實(shí)例

我們通過下面的例子來看看PHOT和HOT的不同之處。

構(gòu)建環(huán)境:

CREATE TABLE test (a INT, b INT, c INT);
CREATE INDEX ON test (a);
CREATE INDEX ON test (b);
CREATE INDEX ON test (c);
INSERT INTO test VALUES (0, 0, 0);
UPDATE test SET a = 1, b = 1;
UPDATE test SET b = 2, c = 2;
UPDATE test SET a = 2;
UPDATE test SET a = 3, c = 3;

不使用PHOT:

可以看到,不使用PHOT的情況下,每次更新都會(huì)產(chǎn)生新的索引元組。

在這些更新之后,有 15 個(gè)索引元組、5 個(gè)行指針和 5 個(gè)堆元組。

test_a_idx 0       1       1       2       3
test_b_idx 0       1       2       2       2
test_c_idx 0       0       2       2       3
lp         1       2       3       4       5
heap       (0,0,0) (1,1,0) (1,2,2) (2,2,2) (3,2,3)

PHOT:

在使用PHOT后,通過增加了一個(gè)bitmap位圖來記錄被更新的列。當(dāng)執(zhí)行完上述更新后,有 10 個(gè)索引元組、5 個(gè)行指針、5 個(gè)堆元組和 4 個(gè)位圖。

test_a_idx 0       1               2       3
test_b_idx 0       1       2
test_c_idx 0               2               3
lp         1       2       3       4       5
heap       (0,0,0) (1,1,0) (1,2,2) (2,2,2) (3,2,3)
bitmap             xx-     -xx     x--     x-x

而前面的例子我們使用PHOT更新又是什么結(jié)果呢?

可以看到下圖中,左邊是使用PHOT進(jìn)行更新的,只是被更新的索引列發(fā)生了變化,而右邊非PHOT進(jìn)行更新則是所有的索引列均發(fā)生變化。

性能測(cè)試:

通過簡單的pgbench測(cè)試,TPS 提高了約 34%,其中每個(gè)表都有 5 個(gè)額外的文本列和每列上的索引。有了額外的索引和列,理論上 TPS 的提升應(yīng)該會(huì)更高。對(duì)于沒有表修改的短期 pgbench 運(yùn)行,使用 PHOT 觀察到 TPS 增加了約 2%,表明常規(guī) pgbench 運(yùn)行沒有受到顯著影響。

總結(jié)

PostgreSQL使用HOT機(jī)制來避免因?yàn)槠涠喟姹咎匦詫?dǎo)致的每次更新數(shù)據(jù)均需要修改索引的情況。而當(dāng)前的HOT機(jī)制,對(duì)于索引列的更新仍然存在比較明顯的性能問題,因?yàn)樗械乃饕枰l(fā)生修改,不過預(yù)計(jì)在PG15中,將會(huì)加入更為強(qiáng)大的PHOT功能,更新索引列再也不會(huì)影響其它索引了。

參考鏈接:

傳送門

傳送門

到此這篇關(guān)于PostgreSQL HOT與PHOT有哪些區(qū)別的文章就介紹到這了,更多相關(guān)PostgreSQL HOT與PHOT內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 在postgresql中運(yùn)行sql文件并導(dǎo)出結(jié)果的操作

    在postgresql中運(yùn)行sql文件并導(dǎo)出結(jié)果的操作

    這篇文章主要介紹了在postgresql中運(yùn)行sql文件并導(dǎo)出結(jié)果的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • postgresql模糊匹配大殺器(推薦)

    postgresql模糊匹配大殺器(推薦)

    這篇文章主要介紹了postgresql模糊匹配大殺器,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • PostgresSql 多表關(guān)聯(lián)刪除語句的操作

    PostgresSql 多表關(guān)聯(lián)刪除語句的操作

    這篇文章主要介紹了PostgresSql 多表關(guān)聯(lián)刪除語句的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • PostgreSQL教程(六):函數(shù)和操作符詳解(2)

    PostgreSQL教程(六):函數(shù)和操作符詳解(2)

    這篇文章主要介紹了PostgreSQL教程(六):函數(shù)和操作符詳解(2),本文講解了模式匹配、數(shù)據(jù)類型格式化函數(shù)、時(shí)間/日期函數(shù)和操作符等內(nèi)容,需要的朋友可以參考下
    2015-05-05
  • PostgreSQL關(guān)閉數(shù)據(jù)庫服務(wù)的三種模式

    PostgreSQL關(guān)閉數(shù)據(jù)庫服務(wù)的三種模式

    PostgreSQL 提供了三種關(guān)閉數(shù)據(jù)庫服務(wù)的不同方式,它們最終都是發(fā)送一個(gè)關(guān)閉信號(hào)到 postgres 主服務(wù)進(jìn)程,本文將給大家詳細(xì)的介紹一下這三種模式,需要的朋友可以參考下
    2024-07-07
  • PostgreSQL基礎(chǔ)知識(shí)之SQL操作符實(shí)踐指南

    PostgreSQL基礎(chǔ)知識(shí)之SQL操作符實(shí)踐指南

    這篇文章主要給大家介紹了關(guān)于PostgreSQL基礎(chǔ)知識(shí)之SQL操作符實(shí)踐的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用PostgreSQL具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • PostgreSQL查詢和處理JSON數(shù)據(jù)

    PostgreSQL查詢和處理JSON數(shù)據(jù)

    這篇文章主要給大家介紹了關(guān)于PostgreSQL查詢和處理JSON數(shù)據(jù)的相關(guān)資料,需要的朋友可以參考下
    2023-11-11
  • PostgreSQL 流復(fù)制異步轉(zhuǎn)同步的操作

    PostgreSQL 流復(fù)制異步轉(zhuǎn)同步的操作

    這篇文章主要介紹了PostgreSQL 流復(fù)制異步轉(zhuǎn)同步的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • 淺談PostgreSQL的客戶端認(rèn)證pg_hba.conf

    淺談PostgreSQL的客戶端認(rèn)證pg_hba.conf

    這篇文章主要介紹了淺談PostgreSQL的客戶端認(rèn)證pg_hba.conf,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • 淺談Postgresql默認(rèn)端口5432你所不知道的一點(diǎn)

    淺談Postgresql默認(rèn)端口5432你所不知道的一點(diǎn)

    這篇文章主要介紹了淺談Postgresql默認(rèn)端口5432你所不知道的一點(diǎn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01

最新評(píng)論