DBA: torganizza b'mod kompetenti sinkronizzazzjonijiet u importazzjonijiet
Għall-ipproċessar kumpless ta’ settijiet kbar ta’ data (differenti Proċessi ETL: importazzjonijiet, konverżjonijiet u sinkronizzazzjoni ma 'sors estern) ħafna drabi jkun hemm bżonn temporanjament "ftakar" u immedjatament ipproċessa malajr xi ħaġa voluminuża.
Kompitu tipiku ta’ dan it-tip normalment jinstema’ xi ħaġa bħal din: "Hawnhekk dipartiment tal-kontabilità ħatt mill-bank klijent l-aħħar pagamenti li rċevejt, trid ittellahom malajr fuq il-websajt u torbothom mal-kontijiet tiegħek.
Iżda meta l-volum ta 'din "xi ħaġa" jibda jitkejjel f'mijiet ta' megabytes, u s-servizz irid ikompli jaħdem mad-database 24x7, jinqalgħu ħafna effetti sekondarji li jħassru ħajtek.
Biex tittrattahom f'PostgreSQL (u mhux fiha biss), tista 'tuża xi ottimizzazzjonijiet li jippermettulek tipproċessa kollox aktar malajr u b'inqas konsum ta' riżorsi.
1. Fejn tibgħat?
L-ewwel, ejja niddeċiedu fejn nistgħu ntellgħu d-dejta li rridu "nipproċessaw."
1.1. Tabelli temporanji (TEMPORARY TABLE)
Fil-prinċipju, għal PostgreSQL it-tabelli temporanji huma l-istess bħal kull ieħor. Għalhekk, superstizzjonijiet bħal "Kollox hemm huwa maħżun biss fil-memorja, u jista 'jispiċċa". Iżda hemm ukoll diversi differenzi sinifikanti.
"Ispazju tal-isem" tiegħek għal kull konnessjoni mad-database
Jekk żewġ konnessjonijiet jippruvaw jgħaqqdu fl-istess ħin CREATE TABLE x, allura xi ħadd definittivament se tikseb żball ta' non-uniċità oġġetti tad-database.
Imma jekk it-tnejn jippruvaw jesegwixxu CREATE TEMPORARY TABLE x, imbagħad it-tnejn se jagħmlu dan b'mod normali, u kulħadd se tikseb kopja tiegħek tabelli. U ma jkun hemm xejn komuni bejniethom.
"Awtoqerda" meta tiskonnettja
Meta l-konnessjoni tingħalaq, it-tabelli temporanji kollha jitħassru awtomatikament, għalhekk manwalment DROP TABLE x m'hemmx skop ħlief...
Jekk qed taħdem permezz pgbouncer fil-modalità tat-tranżazzjoni, allura d-database tkompli temmen li din il-konnessjoni għadha attiva, u fiha din it-tabella temporanja għadha teżisti.
Għalhekk, jekk tipprova terġa' toħloqha, minn konnessjoni differenti għal pgbouncer, tirriżulta fi żball. Iżda dan jista 'jiġi evitat bl-użu CREATE TEMPORARY TABLE IF NOT EXISTS x.
Veru, huwa aħjar li ma tagħmilx dan xorta waħda, għax allura tista '"f'daqqa" ssib hemm id-dejta li fadal mis-"sid preċedenti". Minflok, huwa ħafna aħjar li taqra l-manwal u tara li meta toħloq tabella huwa possibbli li żżid ON COMMIT DROP - jiġifieri, meta t-tranżazzjoni titlesta, it-tabella titħassar awtomatikament.
Non-replikazzjoni
Minħabba li jappartjenu biss għal konnessjoni speċifika, it-tabelli temporanji mhumiex replikati. Iżda dan jelimina l-ħtieġa għal reġistrazzjoni doppja tad-data f'borġ + WAL, għalhekk Daħħal/Aġġorna/ĦAssaS fih huwa ħafna aktar mgħaġġel.
Iżda peress li tabella temporanja għadha tabella "kważi ordinarja", lanqas ma tistax tinħoloq fuq replika. Mill-inqas għalissa, għalkemm il-garża korrispondenti ilha tiċċirkola għal żmien twil.
1.2. TABELLA UNLOGGED
Imma x'għandek tagħmel, pereżempju, jekk għandek xi tip ta 'proċess ETL ingombranti li ma jistax jiġi implimentat fi tranżazzjoni waħda, iżda xorta jkollok pgbouncer fil-modalità tat-tranżazzjoni? ..
Jew il-fluss tad-data huwa tant kbir li M'hemmx biżżejjed bandwidth fuq konnessjoni waħda minn database (aqra, proċess wieħed għal kull CPU)?...
Jew għaddejjin xi operazzjonijiet b'mod mhux sinkroniku f'konnessjonijiet differenti?..
Hemm għażla waħda biss hawn - temporanjament toħloq tabella mhux temporanja. Pun, iva. Jiġifieri:
ħoloq tabelli "tiegħi stess" b'ismijiet massimu każwali sabiex ma jaqsmu ma 'ħadd
Extract: imliethom b'dejta minn sors estern
Transform: konvertiti, mimlija fl-oqsma ewlenin li jgħaqqdu
tagħbija: jitferra data lesta fit-tabelli fil-mira
it-tabelli "tiegħi" imħassra
U issa - fly fl-ingwent. Fil-fatt, il-kitbiet kollha f'PostgreSQL iseħħu darbtejn - l-ewwel f'WAL, imbagħad fil-korpi tabella/indiċi. Dan kollu jsir biex jappoġġja ACID u jikkoreġi l-viżibilità tad-dejta bejn COMMIT‘inkwetat u ROLLBACK‘tranżazzjonijiet nulli.
Imma dan m'għandniex bżonn! Għandna l-proċess kollu Jew kien kompletament suċċess jew ma kienx.. Ma jimpurtax kemm se jkun hemm tranżazzjonijiet intermedji - m'aħniex interessati li "nkomplu l-proċess min-nofs", speċjalment meta ma jkunx ċar fejn kien.
Biex tagħmel dan, l-iżviluppaturi PostgreSQL, lura fil-verżjoni 9.1, introduċew ħaġa bħal tabelli UNLOGGED:
B'din l-indikazzjoni, it-tabella tinħoloq bħala mhux logged. Id-dejta miktuba f’tabelli mhux irreġistrati ma tgħaddix mir-reġistru tal-kitba bil-quddiem (ara l-Kapitolu 29), u b’hekk tabelli bħal dawn taħdem ħafna aktar malajr mis-soltu. Madankollu, mhumiex immuni għall-falliment; f'każ ta' ħsara fis-server jew għeluq ta' emerġenza, tabella mhux logged awtomatikament maqtugħ. Barra minn hekk, il-kontenut tat-tabella mhux logged mhux replikat għal servers slave. Kwalunkwe indiċi maħluqa fuq tabella unlogged awtomatikament issir unlogged.
Fil-qosor, se jkun ħafna aktar mgħaġġel, imma jekk is-server tad-database "jaqa", ikun spjaċevoli. Imma kemm-il darba jiġri dan, u l-proċess tal-ETL tiegħek jaf kif jikkoreġi dan b'mod korrett "minn-nofs" wara li "rivitalizza" id-database?...
Jekk le, u l-każ ta' hawn fuq huwa simili għal tiegħek, uża UNLOGGEDimma qatt ma jippermettux dan l-attribut fuq tabelli reali, id-data li minnha hija għażiża għalik.
1.3. FUQ L-IMPENJA {ĦASSAR RANGELI | qatra}
Dan il-kostrutt jippermettilek li tispeċifika mġiba awtomatika meta titlesta tranżazzjoni meta toħloq tabella.
fuq ON COMMIT DROP Diġà ktibt hawn fuq, tiġġenera DROP TABLE, iżda ma ON COMMIT DELETE ROWS is-sitwazzjoni hija aktar interessanti - hija ġġenerata hawn TRUNCATE TABLE.
Peress li l-infrastruttura kollha għall-ħażna tal-meta-deskrizzjoni ta 'tabella temporanja hija eżattament l-istess bħal dik ta' tabella regolari, allura Il-ħolqien u t-tħassir kostanti ta 'tabelli temporanji jwasslu għal "nefħa" severa tat-tabelli tas-sistema pg_class, pg_attribute, pg_attrdef, pg_depend,...
Issa immaġina li għandek ħaddiem fuq konnessjoni diretta mad-database, li tiftaħ tranżazzjoni ġdida kull sekonda, toħloq, timla, tipproċessa u tħassar tabella temporanja... Se jkun hemm eċċess ta 'żibel akkumulat fit-tabelli tas-sistema, u dan jikkawża brejkijiet żejda għal kull operazzjoni.
B'mod ġenerali, tagħmel dan! F'dan il-każ huwa ħafna aktar effettiv CREATE TEMPORARY TABLE x ... ON COMMIT DELETE ROWS neħħiha miċ-ċiklu tat-tranżazzjoni - imbagħad sal-bidu ta 'kull transazzjoni ġdida t-tabelli diġà huma se teżisti (issejvja sejħa CREATE), iżda se jkun vojt, Grazzi lil TRUNCATE (salvajna wkoll is-sejħa tagħha) meta tlesti t-tranżazzjoni preċedenti.
1.4. LIKE...INKLUŻI...
Semmejt fil-bidu li wieħed mill-każijiet ta 'użu tipiċi għal tabelli temporanji huwa diversi tipi ta' importazzjonijiet - u l-iżviluppatur għajjien jikkopja-pejst il-lista ta 'oqsma tat-tabella fil-mira fid-dikjarazzjoni ta' temporanju tiegħu...
Imma l-għażż huwa l-mutur tal-progress! Għalhekk oħloq tabella ġdida "ibbażata fuq kampjun" jista 'jkun ħafna aktar sempliċi:
CREATE TEMPORARY TABLE import_table(
LIKE target_table
);
Peress li mbagħad tista 'tiġġenera ħafna dejta f'din it-tabella, it-tiftix minnha qatt mhu se jkun mgħaġġel. Iżda hemm soluzzjoni tradizzjonali għal dan - indiċi! U, iva, tabella temporanja jista' jkollha wkoll indiċi.
Peress li, ħafna drabi, l-indiċijiet meħtieġa jikkoinċidu mal-indiċi tat-tabella fil-mira, tista 'sempliċement tikteb LIKE target_table INCLUDING INDEXES.
Jekk għandek bżonn ukoll DEFAULT-valuri (per eżempju, biex timla l-valuri taċ-ċavetta primarja), tista 'tuża LIKE target_table INCLUDING DEFAULTS. Jew sempliċiment - LIKE target_table INCLUDING ALL — tikkopja l-inadempjenzi, l-indiċi, ir-restrizzjonijiet,...
Imma hawn trid tifhem li jekk ħoloqt tabella ta 'importazzjoni immedjatament b'indiċi, allura d-data se tieħu aktar żmien biex titgħabbamilli jekk l-ewwel timla kollox, u mbagħad biss roll up l-indiċi - ħares lejn kif tagħmel dan bħala eżempju pg_dump.
Ħalli ngħid biss - użaha COPY-fluss minflok "pakkett" INSERT, aċċelerazzjoni xi drabi. Tista 'anki direttament minn fajl iġġenerat minn qabel.
3. Kif tipproċessa?
Allura, ejja nħallu l-introduzzjoni tagħna tidher xi ħaġa bħal din:
għandek tabella bid-dejta tal-klijenti maħżuna fid-database tiegħek 1M rekords
kuljum klijent jibgħatlek waħda ġdida "immaġni" sħiħa
mill-esperjenza taf li minn żmien għal żmien mhux aktar minn 10K rekords huma mibdula
Eżempju klassiku ta 'sitwazzjoni bħal din huwa bażi KLADR — b'kollox hemm ħafna indirizzi, iżda f'kull upload ta' kull ġimgħa ftit li xejn ikun hemm bidliet (tismija mill-ġdid ta' insedjamenti, għaqqad ta' toroq, dehra ta' djar ġodda) anke fuq skala nazzjonali.
3.1. Algoritmu ta 'sinkronizzazzjoni sħiħa
Għas-sempliċità, ejja ngħidu li lanqas m'għandek bżonn tirristruttura d-dejta - sempliċement daħħal it-tabella fil-forma mixtieqa, jiġifieri:
neħħi dak kollu li m’għadux jeżisti
aġġornament dak kollu li diġà kien jeżisti u jeħtieġ li jiġi aġġornat
daħħal dak kollu li għadu ma ġarax
Għaliex l-operazzjonijiet għandhom isiru f'din l-ordni? Minħabba li dan huwa kif id-daqs tal-mejda se jikber minimament (ftakar MVCC!).
Ħassar MILL dst
Le, ovvjament tista' tgħaddi b'żewġ operazzjonijiet biss:
neħħi (DELETE) kollox b'mod ġenerali
daħħal kollha mill-immaġni l-ġdida
Iżda fl-istess ħin, grazzi għall-MVCC, Id-daqs tat-tabella se jiżdied eżattament darbtejn! Il-ksib ta' +1M immaġini ta' rekords fit-tabella minħabba aġġornament ta' 10K huwa daqshekk redundancy...
TRUNCATE dst
Żviluppatur b'aktar esperjenza jaf li l-pillola kollha tista 'titnaddaf b'mod pjuttost irħis:
ċara (TRUNCATE) it-tabella kollha
daħħal kollha mill-immaġni l-ġdida
Il-metodu huwa effettiv, kultant pjuttost applikabbli, iżda hemm problema... Se nkunu qed inżidu rekords 1M għal żmien twil, għalhekk ma nistgħux naffordjaw li nħallu t-tabella vojta għal dan iż-żmien kollu (kif jiġri mingħajr ma nkebbewha fi tranżazzjoni waħda).
Li jfisser:
qed nibdew tranżazzjoni fit-tul
TRUNCATE jimponi Aċċess Esklussiva-imblukkar
nagħmlu l-inserzjoni għal żmien twil, u kulħadd f'dan iż-żmien lanqas biss SELECT
Xi ħaġa mhux sejra tajjeb...
ALTER TABLE... êEMMI... / DROP TABLE...
Alternattiva hija li timla kollox f'tabella ġdida separata, u mbagħad sempliċement semmiha mill-ġdid minflok dik l-antika. Ftit affarijiet żgħar koroh:
xorta wkoll Aċċess Esklussiva, għalkemm ħafna inqas ħin
il-pjanijiet/l-istatistika kollha ta' mistoqsijiet għal din it-tabella huma reset, jeħtieġ li tmexxi ANALYZE
ċwievet barranin kollha huma miksura (FK) mat-tabella
Kien hemm garża WIP minn Simon Riggs li ssuġġeriet li tagħmel ALTER-operazzjoni biex tissostitwixxi l-korp tal-mejda fil-livell tal-fajl, mingħajr ma tmiss l-istatistika u FK, iżda ma ġabarx kworum.
Ħassar, Aġġorna, Daħħal
Għalhekk, aħna noqogħdu fuq l-għażla li ma jimblukkawx ta 'tliet operazzjonijiet. Kważi tlieta... Kif tagħmel dan bl-aktar mod effettiv?
-- все делаем в рамках транзакции, чтобы никто не видел "промежуточных" состояний
BEGIN;
-- создаем временную таблицу с импортируемыми данными
CREATE TEMPORARY TABLE tmp(
LIKE dst INCLUDING INDEXES -- по образу и подобию, вместе с индексами
) ON COMMIT DROP; -- за рамками транзакции она нам не нужна
-- быстро-быстро вливаем новый образ через COPY
COPY tmp FROM STDIN;
-- ...
-- .
-- удаляем отсутствующие
DELETE FROM
dst D
USING
dst X
LEFT JOIN
tmp Y
USING(pk1, pk2) -- поля первичного ключа
WHERE
(D.pk1, D.pk2) = (X.pk1, X.pk2) AND
Y IS NOT DISTINCT FROM NULL; -- "антиджойн"
-- обновляем оставшиеся
UPDATE
dst D
SET
(f1, f2, f3) = (T.f1, T.f2, T.f3)
FROM
tmp T
WHERE
(D.pk1, D.pk2) = (T.pk1, T.pk2) AND
(D.f1, D.f2, D.f3) IS DISTINCT FROM (T.f1, T.f2, T.f3); -- незачем обновлять совпадающие
-- вставляем отсутствующие
INSERT INTO
dst
SELECT
T.*
FROM
tmp T
LEFT JOIN
dst D
USING(pk1, pk2)
WHERE
D IS NOT DISTINCT FROM NULL;
COMMIT;
3.2. Ipproċessar wara l-importazzjoni
Fl-istess KLADR, ir-rekords kollha mibdula għandhom jitmexxew addizzjonalment permezz ta 'post-ipproċessar - normalizzati, kliem prinċipali enfasizzati, u mnaqqsa għall-istrutturi meħtieġa. Imma kif taf - x'inbidel eżattmingħajr ma tikkomplika l-kodiċi tas-sinkronizzazzjoni, idealment mingħajr ma tmissu xejn?
Jekk il-proċess tiegħek biss ikollu aċċess għall-kitba fil-ħin tas-sinkronizzazzjoni, allura tista 'tuża grillu li jiġbor il-bidliet kollha għalina:
-- целевые таблицы
CREATE TABLE kladr(...);
CREATE TABLE kladr_house(...);
-- таблицы с историей изменений
CREATE TABLE kladr$log(
ro kladr, -- тут лежат целые образы записей старой/новой
rn kladr
);
CREATE TABLE kladr_house$log(
ro kladr_house,
rn kladr_house
);
-- общая функция логирования изменений
CREATE OR REPLACE FUNCTION diff$log() RETURNS trigger AS $$
DECLARE
dst varchar = TG_TABLE_NAME || '$log';
stmt text = '';
BEGIN
-- проверяем необходимость логгирования при обновлении записи
IF TG_OP = 'UPDATE' THEN
IF NEW IS NOT DISTINCT FROM OLD THEN
RETURN NEW;
END IF;
END IF;
-- создаем запись лога
stmt = 'INSERT INTO ' || dst::text || '(ro,rn)VALUES(';
CASE TG_OP
WHEN 'INSERT' THEN
EXECUTE stmt || 'NULL,$1)' USING NEW;
WHEN 'UPDATE' THEN
EXECUTE stmt || '$1,$2)' USING OLD, NEW;
WHEN 'DELETE' THEN
EXECUTE stmt || '$1,NULL)' USING OLD;
END CASE;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
Issa nistgħu napplikaw triggers qabel ma nibdew is-sinkronizzazzjoni (jew inħalluhom permezz ALTER TABLE ... ENABLE TRIGGER ...):
CREATE TRIGGER log
AFTER INSERT OR UPDATE OR DELETE
ON kladr
FOR EACH ROW
EXECUTE PROCEDURE diff$log();
CREATE TRIGGER log
AFTER INSERT OR UPDATE OR DELETE
ON kladr_house
FOR EACH ROW
EXECUTE PROCEDURE diff$log();
U mbagħad niġbdu bil-kalma l-bidliet kollha li neħtieġu mit-tabelli tar-reġistru u nħaddmuhom permezz ta 'handlers addizzjonali.
3.3. Importazzjoni ta' Settijiet Konnessi
Hawn fuq ikkunsidrajna każijiet meta l-istrutturi tad-dejta tas-sors u tad-destinazzjoni huma l-istess. Imma x'jiġri jekk it-tlugħ minn sistema esterna jkollha format differenti mill-istruttura tal-ħażna fid-database tagħna?
Ejja nieħdu bħala eżempju l-ħażna tal-klijenti u l-kontijiet tagħhom, l-għażla klassika "ħafna għal wieħed":
CREATE TABLE client(
client_id
serial
PRIMARY KEY
, inn
varchar
UNIQUE
, name
varchar
);
CREATE TABLE invoice(
invoice_id
serial
PRIMARY KEY
, client_id
integer
REFERENCES client(client_id)
, number
varchar
, dt
date
, sum
numeric(32,2)
);
Iżda t-tniżżil minn sors estern jiġi għandna fil-forma ta '"kollha f'wieħed":
L-ewwel, ejja nenfasizzaw dawk il-“qatgħat” li għalihom jirreferu l-“fatti” tagħna. Fil-każ tagħna, il-fatturi jirreferu għall-klijenti:
CREATE TEMPORARY TABLE client_import AS
SELECT DISTINCT ON(client_inn)
-- можно просто SELECT DISTINCT, если данные заведомо непротиворечивы
client_inn inn
, client_name "name"
FROM
invoice_import;
Sabiex nassoċjaw b'mod korrett il-kontijiet mal-IDs tal-klijenti, l-ewwel għandna bżonn insibu jew niġġeneraw dawn l-identifikaturi. Ejja nżidu oqsma taħthom:
ALTER TABLE invoice_import ADD COLUMN client_id integer;
ALTER TABLE client_import ADD COLUMN client_id integer;
Ejja nużaw il-metodu ta 'sinkronizzazzjoni tat-tabella deskritt hawn fuq b'emenda żgħira - aħna mhux se naġġornaw jew inħassru xejn fit-tabella fil-mira, għaliex aħna nimportaw klijenti "append-only":
-- проставляем в таблице импорта ID уже существующих записей
UPDATE
client_import T
SET
client_id = D.client_id
FROM
client D
WHERE
T.inn = D.inn; -- unique key
-- вставляем отсутствовавшие записи и проставляем их ID
WITH ins AS (
INSERT INTO client(
inn
, name
)
SELECT
inn
, name
FROM
client_import
WHERE
client_id IS NULL -- если ID не проставился
RETURNING *
)
UPDATE
client_import T
SET
client_id = D.client_id
FROM
ins D
WHERE
T.inn = D.inn; -- unique key
-- проставляем ID клиентов у записей счетов
UPDATE
invoice_import T
SET
client_id = D.client_id
FROM
client_import D
WHERE
T.client_inn = D.inn; -- прикладной ключ
Fil-fatt, kollox jinsab fih invoice_import Issa għandna l-qasam tal-kuntatt mimlija client_id, li biha se ndaħħlu l-fattura.