[英]Incrementally importing data to a PostgreSQL database
情況:
我有一個PostgreSQL數據庫,該數據庫正在現場部署的單元中記錄來自傳感器的數據(我們稱其為源數據庫 )。 該設備的硬盤空間非常有限,這意味着如果不加改動,數據記錄將導致數據庫所在的磁盤在一周內被填滿。 我有一個到數據庫的(非常有限的)網絡鏈接(所以我想壓縮轉儲文件),並且在所說鏈接的另一邊,我有另一個PostgreSQL數據庫(讓我們稱之為目標數據庫 ),其中有很多自由空間(就論點而言,讓我們說,關於空間,源非常有限,關於空間,目的地是無限的)。
我需要對源數據庫進行增量備份,將自上次備份以來已添加的行追加到目標數據庫,然后從源數據庫中清除添加的行。
現在,自從上次執行備份以來,源數據庫可能已被清理,也可能尚未被清理,因此目標數據庫僅需要能夠以自動化(腳本化)過程導入新行,但是pg_restore
在嘗試從數據庫還原時卻失敗了。具有與目標數據庫相同的主鍵號的轉儲。
所以問題是:
什么是從源中僅還原尚未在目標數據庫中的行的最佳方法?
到目前為止,我想出的唯一解決方案是將數據庫pg_dump
並使用pg_restore
將轉儲還原到目標端的新輔助數據庫,然后使用簡單的sql
來整理主目錄中已經存在的行。目標數據庫。 但是似乎應該有更好的方法...
( 額外的問題:在這樣的應用程序中使用PostgreSQL時,我完全錯了嗎?我願意接受其他數據收集替代方案的建議...)
一個好的開始方法可能是對pg_dump
使用--inserts
選項。 從文檔(重點是我的):
將數據轉儲為INSERT命令(而不是COPY)。 這會使恢復非常緩慢。 它主要用於制作可以裝入非PostgreSQL數據庫的轉儲。 但是,由於此選項為每一行生成一個單獨的命令,因此在重新加載行時發生錯誤只會導致該行丟失,而不是整個表內容丟失 。 請注意,如果您重新排列了列順序,則還原可能會完全失敗。 --column-inserts選項可以安全地防止列順序更改,盡管速度更慢。
我現在沒有使用pg_restore
進行測試的方法,但這對於您的情況可能就足夠了。
您還可以使用以下事實:從9.5版開始,PostgreSQL為INSERT提供了ON CONFLICT DO...。 使用一種簡單的腳本語言將它們添加到轉儲中,就可以了。 不幸的是,我沒有找到pg_dump
自動添加的選項。
您可以在Google上“散布連接數據庫同步”以查看相關解決方案。
就我所知,這並不是一個解決得很徹底的問題-有一些常見的解決方法,但是我不知道以數據庫為中心的現成解決方案。
解決此問題的最常見方法是使用消息總線在計算機之間移動事件。 例如,如果您的“源數據庫”只是一個數據存儲,沒有其他邏輯,則您可以擺脫它,並使用消息總線說“事件x已經發生”,然后將該消息總線的端點指向您的“目標計算機”,然后將其寫入數據庫。
您可以考慮使用Apache ActiveMQ或閱讀“ 企業集成模式 ”。
#!/bin/sh
PSQL=/opt/postgres-9.5/bin/psql
TARGET_HOST=localhost
TARGET_DB=mystuff
TARGET_SCHEMA_IMPORT=copied
TARGET_SCHEMA_FINAL=final
SOURCE_HOST=192.168.0.101
SOURCE_DB=slurpert
SOURCE_SCHEMA=public
########
create_local_stuff()
{
${PSQL} -h ${TARGET_HOST} -U postgres ${TARGET_DB} <<OMG0
CREATE SCHEMA IF NOT EXISTS ${TARGET_SCHEMA_IMPORT};
CREATE SCHEMA IF NOT EXISTS ${TARGET_SCHEMA_FINAL};
CREATE TABLE IF NOT EXISTS ${TARGET_SCHEMA_FINAL}.topic
( topic_id INTEGER NOT NULL PRIMARY KEY
, topic_date TIMESTAMP WITH TIME ZONE
, topic_body text
);
CREATE TABLE IF NOT EXISTS ${TARGET_SCHEMA_IMPORT}.tmp_topic
( topic_id INTEGER NOT NULL PRIMARY KEY
, topic_date TIMESTAMP WITH TIME ZONE
, topic_body text
);
OMG0
}
########
find_highest()
{
${PSQL} -q -t -h ${TARGET_HOST} -U postgres ${TARGET_DB} <<OMG1
SELECT MAX(topic_id) FROM ${TARGET_SCHEMA_IMPORT}.tmp_topic;
OMG1
}
########
fetch_new_data()
{
watermark=${1-0}
echo ${watermark}
${PSQL} -h ${SOURCE_HOST} -U postgres ${SOURCE_DB} <<OMG2
\COPY (SELECT topic_id, topic_date, topic_body FROM ${SOURCE_SCHEMA}.topic WHERE topic_id >${watermark}) TO '/tmp/topic.dat';
OMG2
}
########
insert_new_data()
{
${PSQL} -h ${TARGET_HOST} -U postgres ${TARGET_DB} <<OMG3
DELETE FROM ${TARGET_SCHEMA_IMPORT}.tmp_topic WHERE 1=1;
COPY ${TARGET_SCHEMA_IMPORT}.tmp_topic(topic_id, topic_date, topic_body) FROM '/tmp/topic.dat';
INSERT INTO ${TARGET_SCHEMA_FINAL}.topic(topic_id, topic_date, topic_body)
SELECT topic_id, topic_date, topic_body
FROM ${TARGET_SCHEMA_IMPORT}.tmp_topic src
WHERE NOT EXISTS (
SELECT *
FROM ${TARGET_SCHEMA_FINAL}.topic nx
WHERE nx.topic_id = src.topic_id
);
OMG3
}
########
delete_below_watermark()
{
watermark=${1-0}
echo ${watermark}
${PSQL} -h ${SOURCE_HOST} -U postgres ${SOURCE_DB} <<OMG4
-- delete not yet activated; COUNT(*) instead
-- DELETE
SELECT COUNT(*)
FROM ${SOURCE_SCHEMA}.topic WHERE topic_id <= ${watermark}
;
OMG4
}
######## Main
#create_local_stuff
watermark="`find_highest`"
echo 'Highest:' ${watermark}
fetch_new_data ${watermark}
insert_new_data
echo 'Delete below:' ${watermark}
delete_below_watermark ${watermark}
# Eof
這只是一個例子。 一些注意事項:
postgres
身份運行,您可能需要更改此設置 count(*)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.