digoal / blog

Opensource,Database,AI,Business,Minds. git clone --depth 1 https://github.com/digoal/blog
https://github.com/digoal/blog/blob/master/README.md
GNU General Public License v2.0
8.1k stars 1.9k forks source link

關於 postgresql page size 疑問 #103

Closed isdaniel closed 3 years ago

isdaniel commented 3 years ago

我之前是使用 SqlServer 最近在研究 postgresql

這邊想要請問一下 有關於 postgresql page size 的問題

我在官網看到 postgresql page default 大小也是 8K

但我實驗過後好像跟我預期的不一樣不知道是我哪裡有理解錯誤

https://www.postgresql.org/docs/9.0/storage-page-layout.html

我建立一個資料表 t8 並建立一個


CREATE TABLE t8 (id char(8000));

CREATE UNIQUE INDEX  ix_t8 on t8(id);
insert into t8 (id) values (repeat('A',8000));
insert into t8 (id) values (repeat('B',8000));
insert into t8 (id) values (repeat('C',8000));
insert into t8 (id) values (repeat('D',8000));
analyze t8;

select relpages,reltuples,relkind,oid  from pg_class where relname in ('t8','ix_t8');

理論上上面新增3筆資料 (每筆8000 byte字元)

但我利用 pg_class 查看 table 跟 index 數量都沒到 3(預期數量是要3或4 因為有page header)

analyze t8;
select relpages,reltuples,relkind,oid  from pg_class where relname in ('t8','ix_t8')

| relpages | reltuples | relkind | oid   |
|----------|-----------|---------|-------|
|        1 |         4 | r       | 24610 |
|        2 |         4 | i       | 24628 |

另外我下面有對於 t9 資料表測試(int 4 byte,每次新增2000筆資料 理論上是1個page 8K)

CREATE TABLE t9 (id int);
CREATE UNIQUE INDEX  ix_t9 on t9(id);

insert into t9 select generate_series(1,2000);
insert into t9 select generate_series(2001,4000);

analyze t9;
select relpages,reltuples,relkind,oid  from pg_class where relname in ('t9','ix_t9');

但執行結果出乎我意料,table page是18 index page是13

| relpages | reltuples | relkind | oid   |
|----------|-----------|---------|-------|
|       18 |      4000 | r       | 24629 |
|       13 |      4000 | i       | 24632 |

所以我這邊有兩個疑問想要請教大大們

  1. 對於t8 為什麼 table page 跟 index page 數量都沒到 3 (預期數量會大於3)
  2. 對於t9 為什麼數量分別是 table page = 18,index page = 13 在我預期應該是 2 左右
digoal commented 3 years ago

pg会自动对超出2000字节的字段进行压缩, 你可以看一下是不是存储到toast切片表里面了

isdaniel commented 3 years ago

感謝 @digoal 德哥回答 我來看一下 toast 不壓縮是否大小對的上 另外請問一下德哥 是否有辦法查看 複合式Index 的 most_common_valsmost_common_freqs.

在SQL Server是對於Index來建立不同的統計資訊跟資料分佈 直方圖

例如此圖 我網路上找的範例圖

image

可以查看到 複合式Index 組合的密度 還有 下方的資料分佈統計資訊

想請問是否有辦法查詢到複合式Index 資料分佈的統計資訊 (most_common_valsmost_common_freqs)

我查了許多資料都說透過 pg_stats 查看欄位資料分佈並沒有涉及到Index統計分佈

如果此題需要另外開 Issue 我可以再另外處理 謝謝

isdaniel commented 3 years ago

pg会自动对超出2000字节的字段进行压缩, 你可以看一下是不是存储到toast切片表里面了

@digoal 德哥 我查看 t8 資料的確會存在 toast 如果改成 external 就會存在 page 中size也可以對的起來.

但我還是不了解 為什麼 t9 資料表 會使用超過 10 個 page.

因為裡面有 4000 筆 int 資料,理論上是 4000 4 byte = 16kb, 大約等於 16kb = 8kb 2

所以 page 應該只有2個左右 但我看 t9 並沒有存放在 toast 上

select relpages,reltuples,relkind,oid,relfilenode,reltoastrelid  
from pg_class where relname in ('t9','ix_t9');

利用上面語法查詢如下圖

image

CREATE TABLE t9 (id int);
CREATE UNIQUE INDEX  ix_t9 on t9(id);

insert into t9 select generate_series(1,2000);
insert into t9 select generate_series(2001,4000);

analyze t9;
select relpages,reltuples,relkind,oid  from pg_class where relname in ('t9','ix_t9');

                             Table "public.t9"
 Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description
--------+---------+-----------+----------+---------+---------+--------------+-------------
 id     | integer |           |          |         | plain   |              |
Indexes:
    "ix_t9" UNIQUE, btree (id)

經查詢 http://www.postgres.cn/docs/9.5/pageinspect.html

我透過 bt_page_itemsheap_page_items 查看資料存儲資訊 發現每個block 到 row 226 就結束了 我看明明還有空間可以儲存 但資料卻存在另一個 block 中

select *
from heap_page_items(get_raw_page('t9',0));

SELECT * 
FROM bt_page_items('ix_t9',1);

image

image

isdaniel commented 3 years ago

pg会自动对超出2000字节的字段进行压缩, 你可以看一下是不是存储到toast切片表里面了

@digoal 德哥 我查看 t8 資料的確會存在 toast 如果改成 external 就會存在 page 中size也可以對的起來.

但我還是不了解 為什麼 t9 資料表 會使用超過 10 個 page.

因為裡面有 4000 筆 int 資料,理論上是 4000 4 byte = 16kb, 大約等於 16kb = 8kb 2

所以 page 應該只有2個左右 但我看 t9 並沒有存放在 toast 上

select relpages,reltuples,relkind,oid,relfilenode,reltoastrelid  
from pg_class where relname in ('t9','ix_t9');

利用上面語法查詢如下圖

image

CREATE TABLE t9 (id int);
CREATE UNIQUE INDEX  ix_t9 on t9(id);

insert into t9 select generate_series(1,2000);
insert into t9 select generate_series(2001,4000);

analyze t9;
select relpages,reltuples,relkind,oid  from pg_class where relname in ('t9','ix_t9');

                             Table "public.t9"
 Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description
--------+---------+-----------+----------+---------+---------+--------------+-------------
 id     | integer |           |          |         | plain   |              |
Indexes:
    "ix_t9" UNIQUE, btree (id)

經查詢 http://www.postgres.cn/docs/9.5/pageinspect.html

我透過 bt_page_itemsheap_page_items 查看資料存儲資訊 發現每個block 到 row 226 就結束了 我看明明還有空間可以儲存 但資料卻存在另一個 block 中

select *
from heap_page_items(get_raw_page('t9',0));

SELECT * 
FROM bt_page_items('ix_t9',1);

image

image

@digoal 德哥 這個問題 我找到原因了

我想應該是 Database Page Layout

每個 tuples 都有 HeapTupleHeaderData 導致.

我想原因應該是 樂觀鎖 需要紀錄 row version 狀態,而sqlserver是悲觀鎖 所以不用每筆資料都有metadata.

詳細資料 我有寫一篇文章 整理

https://isdaniel.github.io/postgresql-page-deepknow/