postgresql基礎學習(二)——TOAST,分割槽表
目錄
TOAST簡介
全稱The Oversized-Attributes Storage Technique,超大欄位儲存技術。
PG頁面(block)通常為8kb,不允許跨越多個頁面。大欄位(超過1/4 blocksize)會被壓縮 或者 分片成多行存到另一張系統表——TOAST表。
只有變長的資料型別才能支援TOAST。( 定長的大欄位如何處理? 暫不知道,日後再說)
變長型別
bit0 | bit1 | bits 2~31 | N bytes |
壓縮標誌 | 行外標誌 | length | value or pointer |
前2 bits為標誌位,30bits長度,value實際長度,非壓縮後長度。
壓縮標誌,如果置1,那麼value是壓縮的。
行外標誌,如果置1,那麼長度後面的value將是一個指標,指標指向TOAST表中的位置。
TRUNK
行外儲存切成多個chunk塊,chunk為四分之一block大小。
TOAST表裡包含N個chunk塊,每一個chunk塊當做一個獨立的行。
trunk_id | trunk_seq | trunk_data |
OID | 序列號 | 實際資料 |
TOAST指標資料:TOAST‘s oid, chunk_id(oid), 未壓縮資料長度,壓縮後資料長度。共20 bytes
TOAST策略
PLAIN:避免壓縮和行外儲存
EXTENDED:允許壓縮和行外儲存,先壓縮,猶大則行外存
EXERNA:允許行外存,不虛壓縮
MAIN: 允許壓縮,禁止行外存
指定策略
testdb=# ALTER TABLE t2 ALTER title SET STORAGE MAIN;
ALTER TABLE
testdb=# \d+ t2
Table "public.t2"
Column | Type | Modifiers | Storage | Stats target | Description
--------+---------+-----------+---------+--------------+-------------
id | integer | | plain | |
title | text | | main | |
testdb=#
heap-only tuple技術簡介
表上設定儲存引數fillfactor,這個叫填充因子,設定一個數據塊中只寫入百分之多少,剩下的部分不再填充
那剩下的空間幹嘛用呢 ? 資料更新。
當更新一條資料,如果有空閒空間,直接再後面插入一條新的資料,再把舊行和新行形成連結串列。
這樣不需要更新索引,也可以快速找到更新後的資料。
如圖所示更新data1, 將新資料填入該block空閒部分,再將data1->next 指向新資料。
表繼承
類似於C++等面向物件的語言中類的繼承,PostgreSql支援表繼承。
Select父表,會顯示其下所有子表的資料。
舉例,父表computer, 子表有dell和hasee。
testdb=# select * from only computer;
name | cpu | memory
-------+----------+--------
oldPC | i5-4570k | 12
(1 row)
testdb=# select * from computer;
name | cpu | memory
---------------+-----------+--------
oldPC | i5-4570k | 12
laptop_ck | i5-8250u | 12
andoverlaptop | i7-7700hq | 16
gamebook | i7-8579H | 8
(4 rows)
testdb=#
testdb=#
testdb=# select * from dell;
name | cpu | memory | model
---------------+-----------+--------+-------------
laptop_ck | i5-8250u | 12 | 15E8525
andoverlaptop | i7-7700hq | 16 | inspire5000
(2 rows)
testdb=# select * from hasee;
name | cpu | memory | model | usedfor | graphisc
----------+----------+--------+----------+---------+----------
gamebook | i7-8579H | 8 | z7m-kp7s | Game | 1050Ti
(1 row)
testdb=# \d+ computer
Table "public.computer"
Column | Type | Modifiers | Storage | Stats target | Description
--------+---------+-----------+----------+--------------+-------------
name | text | | extended | |
cpu | text | | extended | |
memory | integer | | plain | |
Child tables: dell,
hasee
testdb=#
分割槽表
分割槽表是通過繼承來實現。 父表不定義任何約束條件,N個子表與父表一樣結構,子表加約束條件。
按照一定規則,把資料分別儲存到不同的子表裡面去。
分割槽表的好處是啥?
1. 按時間分割槽,刪除歷史資料很快,舊資料也可以遷移到便宜慢速的儲存介質
2. 按時間分割槽,近時間高頻使用的分割槽表索引可以完全快取到記憶體
3. 一個分割槽是集中的,針對一個分割槽的操作,不會像大表一樣離散
建立步驟:
1. 建立父表,不定義任何檢查約束
2. 建立幾個字表,一般不增加欄位
3. 分割槽表增加約束
4. 分割槽表字段增加索引
5. 定義規則or觸發器,對主表的操作重定向到分割槽表。這一點很像面向物件的多型。
分割槽表操作
建立父表
testdb=# create table mileage_detail(
testdb(# plate_number varchar(10) not null,
testdb(# mdate date not null,
testdb(# mileage int not null,
testdb(# brand varchar(10),
testdb(# model varchar (10),
testdb(# PRIMARY KEY(plate_number, mdate)
testdb(# );
CREATE TABLE
testdb=#
testdb=# \d
List of relations
Schema | Name | Type | Owner
--------+----------------+-------+----------
public | computer | table | postgres
public | dell | table | postgres
public | hasee | table | postgres
public | mileage_detail | table | postgres
public | t1 | table | postgres
public | t2 | table | postgres
(6 rows)
testdb=#
testdb=# \d+ mileage_detail
Table "public.mileage_detail"
Column | Type | Modifiers | Storage | Stats target | Description
--------------+-----------------------+-----------+----------+--------------+-------------
plate_number | character varying(10) | not null | extended | |
mdate | date | not null | plain | |
mileage | integer | not null | plain | |
brand | character varying(10) | | extended | |
model | character varying(10) | | extended | |
Indexes:
"mileage_detail_pkey" PRIMARY KEY, btree (plate_number, mdate)
testdb=#
testdb=#
建立子表
create table mileage_detail_y2018m09(CHECK (mdate >= DATE '2018-09-01'
AND mdate < DATE '2018-10-01')) INHERITS(mileage_detail);
create table mileage_detail_y2018m10(CHECK (mdate >= DATE '2018-10-01'
AND mdate < DATE '2018-11-01')) INHERITS(mileage_detail);
create table mileage_detail_y2018m11(CHECK (mdate >= DATE '2018-11-01'
AND mdate < DATE '2018-12-01')) INHERITS(mileage_detail);
testdb=# \d+ mileage_detail
Table "public.mileage_detail"
Column | Type | Modifiers | Storage | Stats target | Description
--------------+-----------------------+-----------+----------+--------------+-------------
plate_number | character varying(10) | not null | extended | |
mdate | date | not null | plain | |
mileage | integer | not null | plain | |
brand | character varying(10) | | extended | |
model | character varying(10) | | extended | |
Indexes:
"mileage_detail_pkey" PRIMARY KEY, btree (plate_number, mdate)
PROCEDURE mileage_detail_insert_trigger()
Child tables: mileage_detail_y2018m09,
mileage_detail_y2018m10,
mileage_detail_y2018m11
建立子表索引
CREATE INDEX mileage_detail_y2018m09_mdate ON mileage_detail_y2018m09 (mdate);
CREATE INDEX mileage_detail_y2018m10_mdate ON mileage_detail_y2018m10 (mdate);
CREATE INDEX mileage_detail_y2018m11_mdate ON mileage_detail_y2018m11 (mdate);
建立觸發器:
觸發函式
CREATE OR REPLACE FUNCTION mileage_detail_insert_trigger()
RETURNS TRIGGER AS $$
BEGIN
IF (NEW.mdate >= DATE '2018-09-01' AND NEW.mdate < DATE '2018-10-01') THEN
INSERT INTO mileage_detail_y2018m09 VALUES (NEW.*);
ELSIF (NEW.mdate >= DATE '2018-10-01' AND NEW.mdate < DATE '2018-11-01') THEN
INSERT INTO mileage_detail_y2018m10 VALUES (NEW.*);
ELSIF (NEW.mdate >= DATE '2018-11-01' AND NEW.mdate < DATE '2018-12-01') THEN
INSERT INTO mileage_detail_y2018m11 VALUES (NEW.*);
ELSE
RAISE EXCEPTION 'Date out of range. Fix the mileage_detail_insert_trigger function';
END IF;
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
觸發器
觸發器
CREATE TRIGGER insert_mileage_detail_trigger
BEFORE INSERT ON mileage_detail
FOR EACH ROW EXECUTE PROCEDURE mileage_detail_insert_trigger ();
testdb=# \d+ mileage_detail
Table "public.mileage_detail"
Column | Type | Modifiers | Storage | Stats target | Description
--------------+-----------------------+-----------+----------+--------------+-------------
plate_number | character varying(10) | not null | extended | |
mdate | date | not null | plain | |
mileage | integer | not null | plain | |
brand | character varying(10) | | extended | |
model | character varying(10) | | extended | |
Indexes:
"mileage_detail_pkey" PRIMARY KEY, btree (plate_number, mdate)
Triggers:
insert_mileage_detail_trigger BEFORE INSERT ON mileage_detail FOR EACH ROW EXECUTE PROCEDURE mileage_detail_insert_trigger()
Child tables: mileage_detail_y2018m09,
mileage_detail_y2018m10,
mileage_detail_y2018m11
testdb=#
testdb=#
驗證觸發器分表
testdb=#
testdb=# INSERT INTO mileage_detail VALUES('AJ1E08', DATE '2018-09-05', 10000, 'toyota', 'corolla');
INSERT 0 0
testdb=# INSERT INTO mileage_detail VALUES('AJ1E08', DATE '2018-09-07', 10200, 'toyota', 'corolla');
INSERT 0 0
testdb=#
testdb=#
testdb=# INSERT INTO mileage_detail VALUES('AJ1E08', DATE '2018-10-22', 11200, 'toyota', 'corolla');
INSERT 0 0
testdb=#
testdb=# INSERT INTO mileage_detail VALUES('AJ1E08', DATE '2018-11-21', 12200, 'toyota', 'corolla');
INSERT 0 0
testdb=#
testdb=# select * from mileage_detail
testdb-# ;
plate_number | mdate | mileage | brand | model
--------------+------------+---------+--------+---------
AJ1E08 | 2018-09-05 | 10000 | toyota | corolla
AJ1E08 | 2018-09-07 | 10200 | toyota | corolla
AJ1E08 | 2018-10-22 | 11200 | toyota | corolla
AJ1E08 | 2018-11-21 | 12200 | toyota | corolla
(4 rows)
testdb=# select * from mileage_detail
mileage_detail mileage_detail_y2018m09 mileage_detail_y2018m10 mileage_detail_y2018m11
testdb=# select * from mileage_detail_y2018m09
testdb-# ;
plate_number | mdate | mileage | brand | model
--------------+------------+---------+--------+---------
AJ1E08 | 2018-09-05 | 10000 | toyota | corolla
AJ1E08 | 2018-09-07 | 10200 | toyota | corolla
(2 rows)
testdb=# select * from mileage_detail_y2018m10;
plate_number | mdate | mileage | brand | model
--------------+------------+---------+--------+---------
AJ1E08 | 2018-10-22 | 11200 | toyota | corolla
(1 row)
testdb=# select * from mileage_detail_y2018m11;
plate_number | mdate | mileage | brand | model
--------------+------------+---------+--------+---------
AJ1E08 | 2018-11-21 | 12200 | toyota | corolla
(1 row)
testdb=#
分割槽表貌似實現了多型,按照觸發規則自動分類資料,便於日後資料的操作。
小結:
這一篇介紹了對於行外儲存COAST表,分割槽表等內容。後面將學習事件觸發器、表空間、檢視等。