日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Postgresql杂谈 10—Postgresql中的分区表

發(fā)布時間:2024/1/8 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Postgresql杂谈 10—Postgresql中的分区表 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、關(guān)于分區(qū)表

? ? ? ?表分區(qū)是在大數(shù)據(jù)優(yōu)化中的一種常見的分表方案,通過將大數(shù)據(jù)按照一定的規(guī)則(最常見的是按照時間)進行分表處理,將邏輯上的一個大表分割成物理上的幾塊表,插入數(shù)據(jù)時,數(shù)據(jù)會自動插入到不同的分區(qū)表中,從而實現(xiàn)查詢或者其它操作的性能優(yōu)化。相比于一個大表,分區(qū)表具有以下優(yōu)點:

(1)當查詢或者更新一個分區(qū)的大部分記錄時,采用順序掃描而不是隨機掃描,可以獲得巨大的性能提升。

(2)使用不頻繁的歷史數(shù)據(jù)可以轉(zhuǎn)移到一些低廉的存儲介質(zhì)上,而熱數(shù)據(jù)放到性能較好的存儲介質(zhì)上,可以最大限度的減少成本。

(3)位于同一個分區(qū)的熱數(shù)據(jù)可以全部緩存到內(nèi)存中,查詢hit的幾率更高,可以加快查詢速度。

? ? ? ?Postgresql中有兩種建立分區(qū)表的方法——使用聲明式分區(qū)和表繼承分區(qū),接下來,筆者就這兩種方式分別進行介紹。

二、聲明式分區(qū)

? ? ? ?聲明式分區(qū)的意思就是Postgresql提供了相應(yīng)的DDL語句創(chuàng)建分區(qū)表,使用聲明式的方法建立分區(qū)表的方法比較簡單,下面,我們就使用一個例子來介紹這種創(chuàng)建分區(qū)表的方法。

? ? ? ?假設(shè),我們創(chuàng)建一個operate_log表,用來記錄用戶的操作記錄。因為操作記錄會隨著時間的累積,越來越大,所以我們選擇建立一個分區(qū)表,并按照時間分區(qū),每一個一個分區(qū)。

stock_analysis_data=# create table operate_log (id int,user_id int,operate_type int,content text,operate_date date) partition by range(operate_date); CREATE TABLE

? ? ? ?注意partition by range這段語句,是在指明使用哪個字段進行分區(qū)。現(xiàn)在,我們只是創(chuàng)建了分區(qū)表的基礎(chǔ)表,分區(qū)表目前是還沒有創(chuàng)建,基礎(chǔ)表是無法插入數(shù)據(jù)的。此時,向基礎(chǔ)表里面插入數(shù)據(jù),會報下面的錯誤:

stock_analysis_data=# insert into operate_log values(1,1,1,'用戶注冊','2021-06-24'); ERROR: no partition of relation "operate_log" found for row DETAIL: Partition key of the failing row contains (operate_date) = (2021-06-24). stock_analysis_data=#

? ? ? ?接下來,我們來創(chuàng)建該基礎(chǔ)表的分區(qū)表:

stock_analysis_data=# create table operater_log_202106 partition of operate_log for values from ('2021-06-01') to ('2021-07-01'); CREATE TABLE

? ? ? ?可以看到,創(chuàng)建分區(qū)表最關(guān)鍵的兩個語句是:

(1)partition of —— 指定待分區(qū)的基礎(chǔ)表是哪個

(2)for values from () to () —— 指定當前分區(qū)表的分區(qū)范圍

? ? ? ?現(xiàn)在,我們可以向基礎(chǔ)表里面插入數(shù)據(jù),它可以自動的插入到相應(yīng)的分區(qū)中:

stock_analysis_data=# insert into operate_log values(1,1,1,'用戶注冊','2021-06-24'); INSERT 0 1 stock_analysis_data=# select * from operater_log_202106;id | user_id | operate_type | content | operate_date ----+---------+--------------+----------+--------------1 | 1 | 1 | 用戶注冊 | 2021-06-24 (1 row)

? ? ? ?從基礎(chǔ)表里面直接select,可以查詢到分區(qū)表里面的數(shù)據(jù):

stock_analysis_data=# select * from operate_log;id | user_id | operate_type | content | operate_date ----+---------+--------------+----------+--------------1 | 1 | 1 | 用戶注冊 | 2021-06-24 (1 row)

? ? ? ?但是,如果插入定義在分區(qū)范圍之外的數(shù)據(jù),就會報錯:

stock_analysis_data=# insert into operate_log values(1,1,1,'用戶注冊','2021-07-24'); ERROR: no partition of relation "operate_log" found for row DETAIL: Partition key of the failing row contains (operate_date) = (2021-07-24). stock_analysis_data=#

三、表繼承方式實現(xiàn)分區(qū)表

? ? ? ?Postgresql中所謂的表繼承,就是我們在創(chuàng)建一個新表時,可以繼承基礎(chǔ)表,新表具有基礎(chǔ)表的所有字段。而向新表中插入數(shù)據(jù)時,通過基礎(chǔ)表也可以查詢到這些數(shù)據(jù)。實際上,使用聲明式方式創(chuàng)建分區(qū)表,內(nèi)部實現(xiàn)就是利用表繼承。我們還是利用operate_log表作為基礎(chǔ)表,利用表繼承的方式創(chuàng)建分區(qū)表。不過在此之前,我們需要先把原來的operate_log表drop掉,因為通過表繼承的方式實現(xiàn)的分區(qū)表,基礎(chǔ)表必須是普通表,而之前的operate_log表我們創(chuàng)建時聲明成了partition。

stock_analysis_data=# drop table operate_log; DROP TABLE stock_analysis_data=# create table operate_log (id int,user_id int,operate_type int,content text,operate_date date); CREATE TABLE

? ? ? ?下面,以新的operate_log為基礎(chǔ)表,進行分區(qū)表的創(chuàng)建:

stock_analysis_data=# create table operate_log_202105(check(operate_date>='2021-05-01' and operate_date<'2020-06-01')) inherits (operate_log); CREATE TABLE stock_analysis_data=# create table operate_log_202106(check(operate_date>='2021-06-01' and operate_date<'2020-07-01')) inherits (operate_log); CREATE TABLE

? ? ? ?可以看到,以表繼承的方式創(chuàng)建分區(qū)表時需要使用inherits關(guān)鍵字顯式的指明基礎(chǔ)表,而且需要自己寫檢查約束來約束分區(qū)字段的取值范圍。僅僅完成上述工作之后,你會發(fā)現(xiàn),現(xiàn)在的分區(qū)表實際上還無法使用,我們向基礎(chǔ)表里面插入數(shù)據(jù)時,并不能自動的插入到分區(qū)表中。

stock_analysis_data=# insert into operate_log values(1,1,1,'用戶注冊','2021-06-24'); INSERT 0 1

? ? ? ?上述命令,向基礎(chǔ)表operate_log里面插入了一條數(shù)據(jù),按理來說,應(yīng)該插入到operate_log_202106表中,但是實際上,并沒有插入進去:

stock_analysis_data=# select * from operate_log_202106;id | user_id | operate_type | content | operate_date ----+---------+--------------+---------+-------------- (0 rows)

? ? ? ?原因是我們使用表繼承的方式實現(xiàn)分區(qū)表時,需要自己去控制向主表插入數(shù)據(jù)時,數(shù)據(jù)自動插入分區(qū)表的邏輯。目前主要有兩種方式可以實現(xiàn)這一邏輯:一種是使用觸發(fā)器,另一種是使用自定義Rule。接下來,筆者分別進行介紹。

3.1 使用觸發(fā)器進行數(shù)據(jù)自動插入分區(qū)表

? ? ? ?我們先創(chuàng)建觸發(fā)器函數(shù):

create or replace function operate_log_insert_trigger() returns trigger as $$beginif (NEW.operate_date >= date'2021-06-01' and NEW.operate_date < date'2021-07-01') theninsert into operate_log_202106 values (NEW.*);elsif(NEW.operate_date >= date'2021-05-01' and NEW.operate_date < date'2021-06-01') theninsert into operate_log_202105 values (NEW.*);elseraise exception 'out of range!!!';end if; return null;end; $$ language plpgsql;

? ? ? ?然后創(chuàng)建觸發(fā)器:

create trigger insert_sale_detail_trigger before insert on operate_log for each row execute procedure operate_log_insert_trigger(); CREATE TRIGGER

? ? ? ?接下來,向基礎(chǔ)表中插入數(shù)據(jù):

insert into operate_log values (2,2,1,'用戶退出',date'2021-06-24');

? ? ? ?再從operate_log_202106表中查詢:

stock_analysis_data=# select * from operate_log_202106;id | user_id | operate_type | content | operate_date ----+---------+--------------+----------+--------------2 | 2 | 1 | 用戶退出 | 2021-06-24 (1 row)

3.2 使用自定義Rule進行數(shù)據(jù)自動插入分區(qū)表

? ? ? ?以上是使用觸發(fā)器實現(xiàn)的自動從基礎(chǔ)表中向分區(qū)表插入數(shù)據(jù),接下來,筆者介紹下使用自定義Rule向分區(qū)表中插入數(shù)據(jù)的方法。示例如下:

create rule operate_log_insert_202106 as on insert to operate_log where (operate_date>=date'2021-06-01' and operate_date<date'2021-07-01') do insteadinsert into operate_log values (NEW.*);create rule operate_log_insert_202105 as on insert to operate_log where (operate_date>=date'2021-05-01' and operate_date<date'2021-06-01') do insteadinsert into operate_log values (NEW.*);

? ? ? ?創(chuàng)建好上述規(guī)則之后,同樣可以實現(xiàn)向基礎(chǔ)表插入數(shù)據(jù)時自動插入到相應(yīng)的分區(qū)表,但是和觸發(fā)器相比,自定義的Rule有它自己的特點:

(1) 每次插入數(shù)據(jù)都要檢查,找到合適的規(guī)則然后用insert語句替代原來的insert語句,開銷明顯比觸發(fā)器要大。

(2) 創(chuàng)建的Rule不定義會一定觸發(fā),在COPY插入數(shù)據(jù)時就不能觸發(fā)Rule,但是觸發(fā)器可以正常使用

(3) 當插入的數(shù)據(jù)超過了定義的范圍時,觸發(fā)器會報錯,但是Rule會直接插入到基礎(chǔ)表里。

(4) 不管是觸發(fā)器還是Rule,當我們需要擴展分區(qū)表時,都不得不修改觸發(fā)器函數(shù)或者新建Rule。

四、約束排除

? ? ? ?約束排除是種優(yōu)化分區(qū)表性能的查詢方法,簡單說來就是:在從基礎(chǔ)表進行查詢時,如果where條件包含在某個分區(qū)表約束條件之內(nèi)時。如果打開約束排除,則直接從改分區(qū)表進行查詢,但是如果關(guān)閉約束排除,則遍歷所有分區(qū)表查找。在postgresql.conf文件中可以設(shè)置約束排除開啟或是關(guān)閉:constraint_exclusion = partition (默認開啟),設(shè)置off關(guān)閉。

? ? ? ?在約束排除開啟的情況下,我們用explain查看查詢情況:

stock_analysis_data=# explain (analyze,verbose,costs,buffers,timing) select count(*) from operate_log where operate_date >= date'2021-06-01';QUERY PLAN -----------------------------------------------------------------------------------------------------------------------------------Aggregate (cost=26.05..26.06 rows=1 width=8) (actual time=0.023..0.025 rows=1 loops=1)Output: count(*)Buffers: shared hit=1-> Append (cost=0.00..25.16 rows=357 width=0) (actual time=0.013..0.016 rows=1 loops=1)Buffers: shared hit=1-> Seq Scan on public.operater_log_202106 (cost=0.00..23.38 rows=357 width=0) (actual time=0.010..0.013 rows=1 loops=1)Filter: (operater_log_202106.operate_date >= '2021-06-01'::date)Buffers: shared hit=1Planning Time: 0.193 msExecution Time: 0.065 ms (10 rows)

? ? ? ?關(guān)閉約束排除,找到/var/lib/pgsql/11/data下的postgresql.conf文件,修改:

constraint_exclusion = off

? ? ? ?重啟數(shù)據(jù)庫服務(wù)后,再explain上述查詢語句(或者直接執(zhí)行set constraint_exclusion = off,設(shè)置本次session中的參數(shù)):

stock_analysis_data=# explain (analyze,verbose,costs,buffers,timing) select count(*) from operate_log where operate_date >= date'2021-06-01';QUERY PLAN -----------------------------------------------------------------------------------------------------------------------------------Aggregate (cost=78.16..78.17 rows=1 width=8) (actual time=0.029..0.030 rows=1 loops=1)Output: count(*)Buffers: shared hit=3-> Append (cost=0.00..75.48 rows=1071 width=0) (actual time=0.010..0.022 rows=3 loops=1)Buffers: shared hit=3-> Seq Scan on public.operater_log_202104 (cost=0.00..23.38 rows=357 width=0) (actual time=0.008..0.010 rows=1 loops=1)Filter: (operater_log_202104.operate_date >= '2021-06-01'::date)Buffers: shared hit=1-> Seq Scan on public.operater_log_202105 (cost=0.00..23.38 rows=357 width=0) (actual time=0.003..0.004 rows=1 loops=1)Filter: (operater_log_202105.operate_date >= '2021-06-01'::date)Buffers: shared hit=1-> Seq Scan on public.operater_log_202106 (cost=0.00..23.38 rows=357 width=0) (actual time=0.003..0.004 rows=1 loops=1)Filter: (operater_log_202106.operate_date >= '2021-06-01'::date)Buffers: shared hit=1Planning Time: 0.120 msExecution Time: 0.076 ms (16 rows)

五、總結(jié)

? ? ? ?根據(jù)本文的內(nèi)容,我們可以得到如下結(jié)論:

(1)利用表分區(qū)可以實現(xiàn)將一個大表化整為零,數(shù)據(jù)按照日期或者其它分表規(guī)則劃分到分區(qū)表上,一方面可以加快查詢和更新效率,另一方面可以將不同熱度的數(shù)據(jù)分布到不同的存儲介質(zhì)上,減少部署成本。

(2)表分區(qū)可以使用聲明式分區(qū)或者表繼承分區(qū),前者的內(nèi)部實現(xiàn)實際上也是利用表繼承分區(qū),但是前者使用較為簡單,建議使用聲明式的分區(qū)方式。

(3)使用分區(qū)表時,要開啟約束排除,設(shè)置postgresql.conf文件中的constraint_exclusion = partition(默認值)。

總結(jié)

以上是生活随笔為你收集整理的Postgresql杂谈 10—Postgresql中的分区表的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。