您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關如何在Postgres中處理海量數據以及使用分區,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
我們發現個一個有趣的模式就是,在Postgres數據庫集群中會存在一、兩個表以較快的速度增長, 以量化的方式表示就是數GB或者數TB級別的大表。
通常情況下,這些表中存儲的數據通常是應用程序中的事件跟蹤數據,或者是應用程序日志數據
這種規模的表在數據存儲上不是問題,但是存在其他方面的問題:
查詢性能的降低,更新索引變得緩慢。
維護時間變長,VACUUM(表空間整理)
你需要配置數據在應用中的使用
在數據量隨著時間增長時, 通過使用Postgres表分區可以保證較高的查詢性能, 并且不需要將數據拆分保存在不同的數據存儲區域。
在我們的平臺中我們使用了pg_partman來維護表分區, (廣告:)Heroku 平臺擁有Heroku Postgres,Heroku Redis,Heroku Kafka 存儲編排服務
在我們的控制平臺中,我們擁有一個表, 表中存儲的數據是每個人的數據存儲的狀態變化記錄,在幾個星期以后,我們不需要使用這些信息,
這時,我們使用表分區來完成這樣的動作,在兩星期以后,我們就可以快速刪除這些表, 并且,在此期間其他查詢語句的速度不會受到影響。
要了解在大數據量的情況下,Postgre如何保證較高的性能, 我們需要Postgres 內部是如何 如何使用繼承, 如何手動設置表分區, 學會使用 Postgres 擴展模塊,pg_partman, 你可以學到更多Postgre分區設置和維護方法。
Postgres 具有對表分區通過表繼承的基本支持。 Postgres表繼承 和面向對象中繼承的概念一樣。 表據說是從另一個繼承,當它保持相同的數據定義和接口。 Postgres 中實現表繼承已經很長時間了,這一功能也比較成熟,
看一下在我們的案例中一個表繼承是如何實現的:
CREATE TABLE products ( id BIGSERIAL, price INTEGER created_at TIMESTAMPTZ, updated_at TIMESTAMPTZ ); CREATE TABLE books ( isbn TEXT, author TEXT, title TEXT ) INHERITS (products); CREATE TABLE albums ( artist TEXT, length INTEGER, number_of_songs INTEGER ) INHERITS (products);
在此示例中,產品衍生出書籍和唱片, 這意味著如果一個記錄被插入到書表,它將有所有相同特性的產品表,再加上那書表。 如果對產品表發出的查詢,該查詢將參考產品表,再加上它的所有子信息。
對于此示例,該查詢將參考產品、書籍和唱片。
這是在 Postgres 的默認行為。但是,您也可以發出對里面每個子表去做單獨的查詢
現在,我們有一個把握上繼承在 Postgres,我們將設置手動分區。
分區的基本前提條件是主表存在從繼承的所有其他的孩子。
我們將使用短語子表和分區交替整個安裝過程的其余部分。
活數據不應該存儲在主表上. 相反,當數據往主表寫入的時候, 數據需要重定向到適當的子分區表中去, 此重定向操作通常是使用Postgres觸發器來實現的。 最重要的是,檢查約束放在每一個子表, 這樣,如果直接在子表中插入恰當的數據,則將插入成功。 如果數據不屬于分區,那么就不會存入該分區表中去。
做表分區,你需要選擇一個鍵來決定如何區分分區信息, 讓我們將我們的 Postgres 數據庫中一個非常大型的活動表分區的過程。 對于一個事件表,時間是確定如何拆分出信息的關鍵。 讓我們假定,我們事件表獲取 1000 萬插入在任何給定的天完成, 下面是我們原先的事件表架構︰
CREATE TABLE events ( uuid text, name text, user_id bigint, account_id bigint, created_at timestamptz );
讓我們做幾個更多的假設來證明該示例。 針對事件表運行的聚合查詢僅有每一天的時間框架。 這意味著我們聚合分手小時為任何給定的一天。 我們使用事件表中的數據只有跨越了幾天。之后那個時候,我們不要再查詢數據。最重要的是, 我們有 1000 萬的事件生成的一天。
鑒于這些存在的假設,我們有理由來創建日常分區。 我們使用表中數據的創建時間作為鍵值來對數據進行分區(例如 created_at)
CREATE TABLE events ( uuid text, name text, user_id bigint, account_id bigint, created_at timestamptz ); CREATE TABLE events_20160801 ( CHECK (created_at >= '2016-08-01 00:00:00' AND created_at < '2016-08-02 00:00:00') ) INHERITS (events); CREATE TABLE events_20160802 ( CHECK (created_at >= '2016-08-02 00:00:00' AND created_at < '2016-08-03 00:00:00') ) INHERITS (events);
我們的主表定義為事件表,有兩個子表用來存儲接受到的數據, events_20160801 和 events_20160802。
我們也把它們以確保唯一數據的那一天結束在該分區上的 CHECK 約束。 現在我們需要創建一個觸發器,以確保在主表中輸入任何數據都能夠去尋找正確的分區︰
CREATE OR REPLACE FUNCTION event_insert_trigger() RETURNS TRIGGER AS $$ BEGIN IF ( NEW.created_at >= '2016-08-01 00:00:00'AND NEW.created_at < '2016-08-02 00:00:00' ) THEN INSERT INTO events_20160801 VALUES (NEW.*); ELSIF ( NEW.created_at >= '2016-08-02 00:00:00'AND NEW.created_at < '2016-08-03 00:00:00' ) THEN INSERT INTO events_20160802 VALUES (NEW.*); ELSE RAISE EXCEPTION 'Date out of range. Fix the event_insert_trigger() function!'; END IF; RETURN NULL; END; $$ LANGUAGE plpgsql; CREATE TRIGGER insert_event_trigger BEFORE INSERT ON event FOR EACH ROW EXECUTE PROCEDURE event_insert_trigger();
太好了 !分區創建,觸發功能定義,并且觸發器已添加到事件表。
在這一點上,我的應用程序可以插入事件表上的數據和數據可以定向到適當的分區。
那么問題來了,利用手工操作表分區,會存在很多的失誤, 需要我們自己每次都去手動更新分區,創建觸發器,
我們還沒談論到尚未從數據庫中刪除舊數據。 這樣引入了pg_partman .
Postgres 使用 pg_partman,使使得表分區的管理更加簡便(相較于手動創建分區) 讓我們通過一個實例,這樣做從零開始運行︰
首先,讓我們來加載擴展和創建我們的事件表。 如果你已經有一個大的表定義,pg_partman 文件具有指導意義,如何將該表格轉換成一種使用表分區。
$ heroku pg:psql -a sushi sushi::DATABASE=> CREATE EXTENSION pg_partman; sushi::DATABASE=> CREATE TABLE events ( id bigint, name text, properities jsonb, created_at timestamptz );
繼續使用我們的假設,我們早些時候所作的事件數據。 我們每天產生1000萬的事件,我們的查詢聚合是以天為單位的。 鑒于此,我們要創建按天來創建分區。
sushi::DATABASE=> SELECT create_parent('public.events', 'created\_at', 'time', 'daily');
此命令告訴 pg_partman,使用數據表的create_at列作為鍵來創建分區,
到這里<red>存在的另一個問題是</red>,這一創建分區的命令需要手動執行。
目前尚未實現數據庫的定期分區維護,創建新的表分區,轉移相關數據。
sushi::DATABASE=> SELECT run_maintenance();
run_maintenance() 命令將指示 pg_partman 仔細看看所有被分區的表, 并確定是否需要創建新的分區和摧毀舊分區。 無論應銷毀一個分區或保留選項是否確定。 這個命令都將在終端命令行執行。
我們需要設置定時任務,使用Heroku調度程序來完成這項任務,可以達到目的。 此命令將運行每小時檢查一次數據庫表分區,檢查分區和分區創建都在命令中,
Heroku 調度程序是一個很高效率的服務, 每小時一次的執行頻率并不會對數據庫產生明顯的性能影響.
就是這個,我們已經在Postgres中配置了表分區,它將只是在后端做很少的維護動作,
pg_partman的安裝過程(我們目前所做的)只是表象。
想要了解pg_partman 的更多細節的話,可以查看該拓展模塊的相關文檔.
###第四部分 重要的疑問:我需要使用表分區嗎?
表分區允許你打破了一個非常大的表成許多較小的表,來獲得較高的性能提升.
正如在 '手動設置分區部分章節' 指出,許多挑戰存在時試圖創建并使用表分區自己
使用 pg_partman 可以減輕這種業務負擔。
盡管如此,表分區不是你解決一切問題的首選方案. 應該問一些其他問題來確定使用表分區解決該是否合理︰
你有一個足夠大的數據集存儲在一個表中, 他隨著事件顯著增長么?
數據是不可變的么?不可變是指,將它首次插入之后沒有更新操作么?
你在索引方面是否進行過優化?
經過一段時間以后的數據還有價值么?
存在小范圍的數據查詢么?
可以將大規模的數據歸檔到一種廉價的存儲介質上去么? 或者舊的數據需要做"聚合"或"匯總"計算么?
如果你對所有這些問題的回答是,你可以使用表分區。 總的來說,表分區需要你評估如何使用你的數據, 從大架構的設計角度使用和優化去考慮它 表分區的使用需要你提前規劃,并考慮您的使用模式。 只要你考慮到了這些因素,使用表分區會對你的應用性能提升帶來極大的幫助.
關于如何在Postgres中處理海量數據以及使用分區就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。