com.操操|h视频在线观看免费网站|亚洲国产成人在线|国精产品999免费|A片级片免费播放

當前位置: fuhua-pet->培訓 > PostgreSQL技術大講堂 - 第28講:索引內部結構

PostgreSQL技術大講堂 - 第28講:索引內部結構

2023-09-07作者:firstyuding來源:www.lgjxsb.com

PostgreSQL從小白到專家,是從入門逐漸能力提升的一個系列教程,內容包括對PG基礎的認知、包括安裝使用、包括角色權限、包括維護管理、、等內容,希望對熱愛PG、學習PG的同學們有幫助,歡迎持續(xù)關注CUUG PG技術大講堂。


第28講:索引內部結構


內容1 : PG數(shù)據(jù)庫眾多開放特性概述

內容2 : 索引結構與生長

內容3 : Autovacuum自動維護索引

內容4:btree、hash索引應用場景


PostgreSQL 開放特性概述

開放的數(shù)據(jù)類型接口,使得PG支持超級豐富的數(shù)據(jù)類型,除了傳統(tǒng)數(shù)據(jù)庫支持的類型,還支持GIS,JSON,RANGE,IP,ISBN,圖像特征值,化學,DNA等等擴展的類型,用戶還可以根據(jù)實際業(yè)務擴展更多的類型。

開放的操作符接口,使得PG不僅僅支持常見的類型操作符,還支持擴展的操作符,例如 距離符,邏輯并、交、差符號,圖像相似符號,幾何計算符號等等擴展的符號,用戶還可以根據(jù)實際業(yè)務擴展更多的操作符。

開放的外部數(shù)據(jù)源接口,使得PG支持豐富的外部數(shù)據(jù)源,例如可以通過FDW讀寫MySQL, redis, mongo, oracle, sqlserver, hive, www, hbase, ldap, 等等只要你能想到的數(shù)據(jù)源都可以通過FDW接口讀寫。

開放的語言接口,使得PG支持幾乎地球上所有的編程語言作為數(shù)據(jù)庫的函數(shù)、存儲過程語言,例如plpython , plperl , pljava , plR , plCUDA , plshell等等。用戶可以通過language handler擴展PG的語言支持。

開放的索引接口,使得PG支持非常豐富的索引方法,例如btree , hash , gin , gist , sp-gist , brin , bloom , rum , zombodb , bitmap (greenplum extend),用戶可以根據(jù)不同的數(shù)據(jù)類型,以及查詢的場景,選擇不同的索引。

PG內部還支持BitmapAnd, BitmapOr的優(yōu)化方法,可以合并多個索引的掃描操作,從而提升多個索引數(shù)據(jù)訪問的效率。


索引結構

· PostgreSQL索引結構

meta page和root page是一定有的,meta page需要一個頁來存儲,表示指向root page的page id。

隨著記錄數(shù)的增加,一個root page可能存不下所有的heap item,就會有l(wèi)eaf page,甚至branch page,甚至多層的branch page。

一共有幾層branch 和 leaf,可以用btree page元數(shù)據(jù)的 level 來表示。


Btree索引

· Btree索引


索引工具介紹

· 如何訪問索引結構

1、create extension pageinspect

2、查看meta塊

select * from bt_metap('tab1_pkey');

3、查看root page的stats

select * from bt_page_stats('tab1_pkey',1);

4、查看root(leaf)頁里面的內容:

select * from bt_page_items('tab1_pkey',1);

5、根據(jù)ctid來訪問表:

select * from tab1 where ctid='(0,1)';


Btree索引

· 一層結構

有1層(0)結構,包括meta page, root page


1、環(huán)境準備:

postgres=# create extension pageinspect;

postgres=# create table tab1(id int primary key, info text);

CREATE TABLE

postgres=# insert into tab1 select generate_series(1,100), md5(random()::text);

INSERT 0 100

postgres=# vacuum analyze tab1;

VACUUM


2、查看meta塊

indx=# select * from bt_metap('tab1_pkey');

magic | version | root | level | fastroot | fastlevel | oldest_xact | last_cleanup_num_tuples

--------+---------+------+-------+----------+-----------+-------------+-------------------------

340322 | 4 | 1 | 0 | 1 | 0 | 0 | 100

此時level 0,root塊為1。


3、根據(jù)root page id = 1,查看root page的stats

ndx=# select * from bt_page_stats('tab1_pkey',1);

blkno | type | live_items | dead_items | avg_item_size | page_size | free_size | btpo_prev | btpo_next | btpo | btpo_flags

-------+------+------------+------------+---------------+-----------+-----------+-----------+-----------+------+------------

1 | l | 100 | 0 | 16 | 8192 | 6148 | 0 | 0 | 0 | 3

(1 row)

此時:btpo=0,說明處于第0層。

btpo_flags=3,說明它既是leaf又是root頁。即:root_page(2)+leaf_page(1)=3

注:

meta page

root page :表示為btpo_flags=2

branch page :表示為btpo_flags=0

leaf page :表示為btpo_flags=1


4、查看root(leaf)頁里面的內容:

itemoffset | ctid | itemlen | nulls | vars | data

------------+---------+---------+-------+------+-------------------------

1 | (0,1) | 16 | f | f | 01 00 00 00 00 00 00 00

2 | (0,2) | 16 | f | f | 02 00 00 00 00 00 00 00

3 | (0,3) | 16 | f | f | 03 00 00 00 00 00 00 00

4 | (0,4) | 16 | f | f | 04 00 00 00 00 00 00 00

5 | (0,5) | 16 | f | f | 05 00 00 00 00 00 00 00

此時ctid就是指向表的行id,類似于oracle的rowid,PG中為tid。

data就是索引列的值,16進制。


5、根據(jù)ctid來訪問表:

indx=# select * from tab1 where ctid='(0,1)';

id | info

----+----------------------------------

1 | 7c3402d464509541c0d788e1afe2c90f


6、查看表的數(shù)據(jù)來驗證:

indx=# select * from tab1 limit 2;

id | info

----+----------------------------------

1 | 7c3402d464509541c0d788e1afe2c90f

2 | f19de3e3255b9f1f676584fd50ad73d9


· 二層結構

有2層(0,1)結構,包括meta page, root page, leaf page

準備工作:

繼續(xù)往表中插入數(shù)據(jù),讓索引生長。

insert into tab1 select generate_series(101,10000), md5(random()::text) ;

1、查看meta數(shù)據(jù):

indx=# select * from bt_metap('tab1_pkey');

magic | version | root | level | fastroot | fastlevel | oldest_xact | last_cleanup_num_tuples

--------+---------+------+-------+----------+-----------+-------------+-------------------------

340322 | 4 | 3 | 1 | 3 | 1 | 0 | -1

root塊在第3塊。


2、根據(jù)root page id 查看root page的stats:

indx=# select * from bt_page_stats('tab1_pkey',3);

blkno | type | live_items | dead_items | avg_item_size | page_size | free_size | btpo_prev | btpo_next | btpo | btpo_flags

-------+------+------------+------------+---------------+-----------+-----------+-----------+-----------+------+------------

3 | r | 28 | 0 | 15 | 8192 | 7596 | 0 | 0 | 1 | 2


3、查看root page存儲的 leaf page items (指向leaf page):

indx=# select * from bt_page_items('tab1_pkey',3);

itemoffset | ctid | itemlen | nulls | vars | data

------------+--------+---------+-------+------+-------------------------

1 | (1,0) | 8 | f | f |

2 | (2,1) | 16 | f | f | 6f 01 00 00 00 00 00 00

3 | (4,1) | 16 | f | f | dd 02 00 00 00 00 00 00

一共28個葉塊。data存儲的是這個leaf page存儲的最小值。


4、查看第一個葉塊統(tǒng)計:

indx=# select * from bt_page_stats('tab1_pkey',1);

blkno | type | live_items | dead_items | avg_item_size | page_size | free_size | btpo_prev | btpo_next | btpo | btpo_flags

-------+------+------------+------------+---------------+-----------+-----------+-----------+-----------+------+------------

1 | l | 367 | 0 | 16 | 8192 | 808 | 0 | 2 | 0 | 1

btpo=0,說明是最底層,btpo_flags=1,即葉塊。


5、查看其它葉塊統(tǒng)計,當查詢到第30塊時,顯示超出塊的范圍。

indx=# select * from bt_page_stats('tab1_pkey',29);

blkno | type | live_items | dead_items | avg_item_size | page_size | free_size | btpo_prev | btpo_next | btpo | btpo_flags

-------+------+------------+------------+---------------+-----------+-----------+-----------+-----------+------+------------

29 | l | 118 | 0 | 16 | 8192 | 5788 | 28 | 0 | 0 | 1


6、查看第一個葉塊的內容:

indx=# select * from bt_page_items('tab1_pkey',1);

itemoffset | ctid | itemlen | nulls | vars | data

------------+---------+---------+-------+------+-------------------------

1 | (3,1) | 16 | f | f | 6f 01 00 00 00 00 00 00

2 | (0,1) | 16 | f | f | 01 00 00 00 00 00 00 00

3 | (0,2) | 16 | f | f | 02 00 00 00 00 00 00 00


7、根據(jù)CTID查看表中的行數(shù)據(jù):

select * from t_btree where ctid='(0,1)';

id | info

----+----------------------------------

1 | 9892a864978b60abb3a30e9c23298967


· 三層結構

記錄數(shù)超過1層結構的索引所能夠存儲的記錄數(shù)時,會分裂為2層結構,除了meta page和root page,還可能包含1層branch page以及1層leaf page。

1、繼續(xù)往tab1表插入新數(shù)據(jù),導致btree增長一層:

insert into tab1 select generate_series(10001,100000), md5(random()::text) ;

postgres=# vacuum analyze tab1;


2、查看meta page,可以看到root page id = 412, 索引的level=2,即包括1級 branch 和 1級 leaf。

postgres=# select * from bt_metap('tab1_pkey');

magic | version | root | level | fastroot | fastlevel

--------+---------+------+-------+----------+-----------

340322 | 2 | 412 | 2 | 412 | 2


3、根據(jù)root page id 查看root page的stats

indx=# select * from bt_page_stats('tab1_pkey', 412);

blkno | type | live_items | dead_items | avg_item_size | page_size | free_size | btpo_prev | btpo_next | btpo | btpo_flags

-------+------+------------+------------+---------------+-----------+-----------+-----------+-----------+------+------------

412 | r | 11 | 0 | 15 | 8192 | 7936 | 0 | 0 | 2 | 2

btpo = 2 當前在第二層,另外還表示下層是1。

btpo_flags = 2 說明是root page


4、查看root page存儲的 branch page items (指向branch page)

postgres=# select * from bt_page_items('tab1_pkey', 412);

itemoffset | ctid | itemlen | nulls | vars | data

------------+----------+---------+-------+------+-------------------------

1 | (3,1) | 8 | f | f |

2 | (2577,1) | 16 | f | f | e1 78 0b 00 00 00 00 00

3 | (1210,1) | 16 | f | f | ec 3a 18 00 00 00 00 00

4 | (2316,1) | 16 | f | f | de 09 25 00 00 00 00 00


5、根據(jù)branch page id查看stats

indx=# select * from bt_page_stats('tab1_pkey', 3);

blkno | type | live_items | dead_items | avg_item_size | page_size | free_size | btpo_prev | btpo_next | btpo | btpo_flags

-------+------+------------+------------+---------------+-----------+-----------+-----------+-----------+------+------------

3 | i | 316 | 0 | 15 | 8192 | 1836 | 0 | 2247 | 1 | 0


6、查看branch page存儲的 leaf page ctid (指向leaf page)

indx=# indx=# select * from bt_page_items('tab1_pkey', 3);

itemoffset | ctid | itemlen | nulls | vars | data

------------+----------+---------+-------+------+-------------------------

1 | (1748,1) | 16 | f | f | 32 56 0c 00 00 00 00 00

2 | (1,0) | 8 | f | f |

3 | (3519,1) | 16 | f | f | 47 08 00 00 00 00 00 00

只要不是最右邊的頁,第一條都代表右頁的起始item。

第二條才是當前頁的起始ctid

注意所有branch page的起始item對應的data都是空的。

也就是說它不存儲當前branch page包含的所有l(wèi)eaf pages的索引字段內容的最小值。


7、根據(jù)ctid 查看leaf page的統(tǒng)計:

indx=# select * from bt_page_stats('tab1_pkey', 1);

blkno | type | live_items | dead_items | avg_item_size | page_size | free_size | btpo_prev | btpo_next | btpo | btpo_flags

-------+------+------------+------------+---------------+-----------+-----------+-----------+-----------+------+------------

1 | l | 234 | 0 | 16 | 8192 | 3468 | 0 | 2952 | 0 | 1

btpo = 0 當前在第0層,即最底層,這里存儲的是heap ctid

btpo_flags = 1 說明是leaf page

第0層葉塊,第1層枝塊,第2層root塊。


8、查看leaf頁的指向表的ctid:

indx=# select * from bt_page_items('tab1_pkey', 1);

itemoffset | ctid | itemlen | nulls | vars | data

------------+------------+---------+-------+------+-------------------------

1 | (1509,1) | 16 | f | f | 25 09 00 00 00 00 00 00

2 | (4072,81) | 16 | f | f | 05 00 00 00 00 00 00 00

3 | (1035,12) | 16 | f | f | 07 00 00 00 00 00 00 00


9、通過ctid查看表的數(shù)據(jù):

indx=# select * from tab2 where ctid='(1748,1)';

id | info

---------+----------------------------------

2222345 | aa2555d335e54892040bf20843ee71af


索引案例應用

利用查看索引數(shù)據(jù)塊的變化,去證明Autovacuum是否會維護索引。

1、環(huán)境搭建

create table tbl_test (id int, info text, c_time timestamp);

insert into tbl_test select generate_series(1,100000),md5(random()::text),clock_timestamp();

create index tbl_test_id_ind on tbl_test (id);


2、索引信息

--查看索引元數(shù)據(jù)

select * from bt_metap('tbl_test_id_ind');

--查看索引root根統(tǒng)計

select * from bt_page_stats('tbl_test_id_ind',3);

--查看索引葉塊內容(此時沒有發(fā)生數(shù)據(jù)更新)

indx=# select * from bt_page_items('tbl_test_id_ind',1);

itemoffset | ctid | itemlen | nulls | vars | data

------------+---------+---------+-------+------+-------------------------

1 | (3,1) | 16 | f | f | 6f 01 00 00 00 00 00 00

2 | (0,1) | 16 | f | f | 01 00 00 00 00 00 00 00

3 | (0,2) | 16 | f | f | 02 00 00 00 00 00 00 00

4 | (0,3) | 16 | f | f | 03 00 00 00 00 00 00 00


3、更新表數(shù)據(jù),導致autovacuum觸發(fā)

update tbl_test set info=md5(random()::text) where id < 20060;


4、查看索引葉塊的內容變化(autovacuum前)

indx=# select * from bt_page_items('tbl_test_id_ind',1);

itemoffset | ctid | itemlen | nulls | vars | data

------------+-----------+---------+-------+------+-------------------------

1 | (1,1) | 16 | f | f | a3 00 00 00 00 00 00 00

2 | (0,1) | 16 | f | f | 01 00 00 00 00 00 00 00

3 | (934,63) | 16 | f | f | 01 00 00 00 00 00 00 00

4 | (0,2) | 16 | f | f | 02 00 00 00 00 00 00 00

5 | (934,64) | 16 | f | f | 02 00 00 00 00 00 00 00

6 | (0,3) | 16 | f | f | 03 00 00 00 00 00 00 00

7 | (934,65) | 16 | f | f | 03 00 00 00 00 00 00 00

注意紅色的為被更新的索引行。


5、查看索引葉塊的內容變化(autovacuum后)

indx=# select * from bt_page_items('tbl_test_id_ind',1);

itemoffset | ctid | itemlen | nulls | vars | data

------------+-----------+---------+-------+------+-------------------------

1 | (1,1) | 16 | f | f | a3 00 00 00 00 00 00 00

2 | (934,63) | 16 | f | f | 01 00 00 00 00 00 00 00

3 | (934,64) | 16 | f | f | 02 00 00 00 00 00 00 00

4 | (934,65) | 16 | f | f | 03 00 00 00 00 00 00 00

5 | (934,66) | 16 | f | f | 04 00 00 00 00 00 00 00

觀察后發(fā)現(xiàn)索引塊的信息更新了,原來的索引行被刪除。

說明autovacuum會自動維護索引信息。


索引維護

· 索引維護

testdb=# reindex INDEX id_data_ind2;

Reindex后索引的relfilenode就發(fā)生變化:

testdb=# select relname,oid,relfilenode from pg_class

where relname='id_data_ind2';

relname | oid | relfilenode

--------------+-------+-------------

id_data_ind2 | 65538 | 65546


Btree索引應用場景

· PostgreSQL B-Tree是一種變種(高并發(fā)B樹管理算法)

應用場景

b-tree適合所有的數(shù)據(jù)類型,支持排序,支持大于、小于、等于、大于或等于、小于或等于的搜索。

索引與遞歸查詢結合,還能實現(xiàn)快速的稀疏檢索。

示例

postgres=# create table t_btree(id int, info text);

CREATE TABLE

postgres=# insert into t_btree select generate_series(1,10000), md5(random()::text) ;

INSERT 0 10000

postgres=# create index idx_t_btree_1 on t_btree using btree (id);

CREATE INDEX

postgres=# explain (analyze,verbose,timing,costs,buffers) select * from t_btree where id=1;


· Hash索引結構

哈希索引項只存儲每個索引項的哈希代碼,而不是實際的數(shù)據(jù)值

應用場景

hash索引存儲的是被索引字段VALUE的哈希值,只支持等值查詢。

hash索引特別適用于字段VALUE非常長(不適合b-tree索引,因為b-tree一個PAGE至少要存儲3個索引行,所以不支持特別長的VALUE)的場景,例如很長的字符串,并且用戶只需要等值搜索,建議使用hash index。

示例

postgres=# create table t_hash (id int, info text);

CREATE TABLE

postgres=# insert into t_hash select generate_series(1,100), repeat(md5(random()::text),10000);

INSERT 0 100

-- 使用b-tree索引會報錯,因為長度超過了1/3的索引頁大小

postgres=# create index idx_t_hash_1 on t_hash using btree (info);

ERROR: index row size 3720 exceeds maximum 2712 for index "idx_t_hash_1"

HINT: Values larger than 1/3 of a buffer page cannot be indexed.

Consider a function index of an MD5 hash of the value, or use full text indexing.

postgres=# create index idx_t_hash_1 on t_hash using hash (info);

CREATE INDEX

postgres=# explain (analyze,verbose,timing,costs,buffers) select * from t_hash where info in (select info from t_hash limit 1);

  • ocp認證爛大街了嗎?并未爛大街
  • 在去Oracle環(huán)境下,市場還認可OCP認證嗎?
  • 工業(yè)和信息化部人才交流中心關于培訓考試評價證書更名的通告
  • 簽約!北京某大型檔案館、成都市某科研所與CUUG簽約工信人才PG認證學習
  • PostgreSQL技術大講堂 - 第74講:PostgreSQL SQL調優(yōu)二
  • 恭喜CUUG 11月16日考試的同學獲得PG中級、PG高級證書
  • 推動國內信創(chuàng)數(shù)據(jù)庫發(fā)展,考取信創(chuàng)PostgreSQL認證
  • 為什么要發(fā)展信創(chuàng)數(shù)據(jù)庫-信創(chuàng)PostgreSQL認證
  • 12月6日恭喜CUUG鄭同學通過OCP考試獲得OCP證書
  • OCP是什么意思 OCP有用嗎
  • PostgreSQL技術大講堂 - 第75講:SQL調優(yōu)(3)索引調優(yōu)升級版
  • PostgreSQL技術大講堂 - 第76講:調優(yōu)(4)分區(qū)表索引調優(yōu)
  • PostgreSQL與MySQL相似之處與不同之處
  • 免費學習PostgreSQL,來這里看看PG從小白到專家技術公開課
  • 【重磅消息】Oracle OCP 認證考試,CUUG贈送一次免費補考機會!
  • OCM認證爛大街了嗎?OCM戰(zhàn)袍在此,永不過時!
  • 報名OCP認證考試,送一次免費補考機會,限時活動,名額有限!
  • 恭喜CUUG韓同學通過Oracle考試拿到OCP 19c證書
  • PostgreSQL認證是什么,值得考嗎
  • PostgreSQL證書什么樣子的
  • RAG,搭建PG向量數(shù)據(jù)庫AI機器人(文檔下載+視頻)
  • 從中美貿易戰(zhàn)金融戰(zhàn)科技戰(zhàn),看我國發(fā)展信創(chuàng)的必要性
  • 微軟發(fā)布基于PostgreSQL的開源文檔數(shù)據(jù)庫平臺DocumentDB
  • 信創(chuàng)領域的PostgreSQL管理員認證
  • 2月22日,工信部人才交流中心 & CUUG - PGCP-PGCM認證考試完成!
  • PostgreSQL技術大講堂 - 第81講:PG數(shù)據(jù)安全利器--行級安全策略構建
  • PostgreSQL數(shù)據(jù)庫從入門到精通教程(進行中)
  • 工信部人才交流中心PostgreSQL認證考試 - 聊一下更多精彩
  • 中國PostgreSQL數(shù)據(jù)庫認證體系和學習方向
  • 25年3月通知!騰訊云TDSQL認證考試流程變更,原流程將作廢
  • 2025年2月 恭喜CUUG王同學順利拿到OCP認證證書
  • 2025年騰訊云TDSQL認證考試升級通知
  • MySQL技術公開課:Mysql-Server-8.4.4 Innodb 集群搭建與維護
  • Oracle OCP認證考試指南(超詳細步驟)
  • 為什么去IOE化的背景下,還有必要學Oracle
  • PolarDB for PostgreSQL:OSS 外表
  • 中科方德「方德高可信服務操作系統(tǒng)」通過PolarDB產(chǎn)品生態(tài)集成認證
  • PostgreSQL技術大講堂 - 第77講:DB4AI 搭建PG向量數(shù)據(jù)庫AI機器人
  • PostgreSQL技術大講堂 - 第78講:分布式數(shù)據(jù)庫-GreenPlum應用實踐
  • PostgreSQL技術大講堂 - 第79講:PG流復制管理利器repmgr應用實踐
  • PostgreSQL數(shù)據(jù)庫管理員認證的含金量
  • PostgreSQL技術大講堂 - 第72講:索引與SQL調優(yōu)之禁忌之戀
  • PostgreSQL技術大講堂 - 第73講:AI4DB系列公開課--搭建私域大模型
  • 百期PostgreSQL技術公開課進行時,已講到第73期了
  • 如何建設國內postgresql數(shù)據(jù)庫生態(tài)環(huán)境
  • 1月15日證書來啦!工信部人才交流中心PostgreSQL中級高級認證
  • OCP英文全稱是什么
  • PolarDB PostgreSQL版高可用原理分析
  • 工信部人才交流中心與教育部學生服務與素質發(fā)展中心戰(zhàn)略合作
  • 為什么說開展信創(chuàng)數(shù)據(jù)庫勢在必行