{"id":74953,"date":"2020-03-22T08:42:22","date_gmt":"2020-03-22T05:42:22","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/dba-gramotno-organizovyvaem-sinhronizaczii-i-importy"},"modified":"2020-03-22T08:42:22","modified_gmt":"2020-03-22T05:42:22","slug":"dba-gramotno-organizovyvaem-sinhronizaczii-i-importy","status":"publish","type":"post","link":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/dba-gramotno-organizovyvaem-sinhronizaczii-i-importy","title":{"rendered":"DBA: organizziamo le sincronizzazioni e gli import con competenza","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Nella gestione complessa di grandi quantit\u00e0 di dati (differenti <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/ETL\">processi ETL<\/a><\/noindex>: importazioni, conversioni e sincronizzazioni con fonti esterne) spesso si presenta la necessit\u00e0 <b>di \"memorizzare\" temporaneamente e elaborare rapidamente<\/b> qualcosa di voluminoso.<\/p>\n<p>Un compito tipico di questo tipo suona solitamente cos\u00ec: <i>\u00abEcco qui <noindex><a rel=\"nofollow\" href=\"https:\/\/sbis.ru\/accounting\">la contabilit\u00e0 ha esportato dal client bancario<\/a><\/noindex> i pagamenti ricevuti pi\u00f9 recenti, dobbiamo caricarli velocemente sul sito e abbinarli ai conti\u00bb<\/i><\/p>\n<p>Ma quando la quantit\u00e0 di questo \"qualcosa\" inizia a misurarsi in centinaia di megabyte e il servizio deve continuare a lavorare con il database 24&#215;7, sorgono numerosi effetti collaterali che possono complicarti la vita.<br \/>\n<img decoding=\"async\" alt=\"DBA: organizziamo le sincronizzazioni e gli import con competenza\" src=\"\/wp-content\/uploads\/2020\/03\/f74afb2cd6f5f8de26a0932166933c95.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nPer affrontarli in PostgreSQL (e non solo), si possono utilizzare alcune funzionalit\u00e0 per ottimizzazioni che permetteranno di elaborare tutto pi\u00f9 rapidamente e con un minore consumo di risorse.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>1. Dove caricare?<\/h2>\n<p>\nInnanzitutto, definiamo dove possiamo caricare i dati che vogliamo \"elaborare\".<\/p>\n<h3>1.1. Tabelle temporanee (TEMPORARY TABLE)<\/h3>\n<p>\nIn linea di principio, le tabelle temporanee in PostgreSQL sono come qualsiasi altra tabella. Pertanto, sono infondate le superstizioni del tipo <i><b>\u00abl\u00ec tutto \u00e8 memorizzato solo nella memoria, e questa pu\u00f2 esaurirsi\u00bb<\/b><\/i>. Ma ci sono anche alcune differenze sostanziali.<\/p>\n<h4>Un proprio 'namespace' per ogni connessione al DB<\/h4>\n<p>\nSe due connessioni provano a eseguire simultaneamente <code>CREATE TABLE x<\/code>, allora qualcuno otterr\u00e0 sicuramente <b>un errore di non unicit\u00e0<\/b> degli oggetti del DB.<\/p>\n<p>Ma se entrambi provano a eseguire <code>CREARE <b>TEMPORANEA<\/b> TABELLA x<\/code>, allora entrambi lo faranno correttamente, e ognuno otterr\u00e0 <b>la propria istanza<\/b> della tabella. E non ci sar\u00e0 nulla in comune tra loro.<\/p>\n<h4>\u00abAuto-distruzione\u00bb al momento della disconnessione<\/h4>\n<p>\nQuando viene chiusa una connessione, tutte le tabelle temporanee vengono eliminate automaticamente, quindi non ha senso eseguire <code>DROP TABLE x<\/code> a meno che non sia\u2026<\/p>\n<p>Se stai lavorando tramite <b>pgbouncer in modalit\u00e0 transaction<\/b>, il database continua a considerare che questa connessione sia ancora attiva, e in essa questa tabella temporanea esiste ancora.<\/p>\n<p>Pertanto, il tentativo di crearla nuovamente da un'altra connessione a pgbouncer porter\u00e0 a un errore. Ma questo pu\u00f2 essere aggirato, utilizzando <code>CREA UNA TABELLA TEMPORANEA <b>SE NON ESISTE<\/b> x<\/code>.<\/p>\n<p>\u00c8 vero, sarebbe meglio non farlo, perch\u00e9 si potrebbe poi \"improvvisamente\" scoprire di avere dati lasciati dal \"precedente proprietario\". \u00c8 molto meglio leggere il manuale e vedere che, durante la creazione della tabella, c'\u00e8 l'opzione per aggiungere <code>ALL'IMPEGNO <b>ELIMINA<\/b><\/code> \u2014 cio\u00e8 alla conclusione della transazione, la tabella verr\u00e0 automaticamente eliminata.<\/p>\n<h4>Non-replicazione<\/h4>\n<p>\nIn virt\u00f9 del fatto che appartengono solo a una connessione specifica, le tabelle temporanee non vengono replicate. Tuttavia, <b>questo elimina la necessit\u00e0 di una doppia scrittura dei dati<\/b> in heap + WAL, quindi INSERT\/UPDATE\/DELETE in esse \u00e8 significativamente pi\u00f9 veloce.<\/p>\n<p>Tuttavia, poich\u00e9 una tabella temporanea \u00e8 comunque \"quasi una tabella normale\", non pu\u00f2 essere creata neanche nella replica. Almeno, per ora, anche se la relativa patch circola da tempo.<\/p>\n<h3>1.2. Tabelle non registrabili (UNLOGGED TABLE)<\/h3>\n<p>\nMa cosa fare, ad esempio, se hai un qualche processo ETL ingombrante che non pu\u00f2 essere realizzato all'interno di una singola transazione, e hai <b>pgbouncer in modalit\u00e0 transaction<\/b>?..<\/p>\n<p>Oppure, il flusso di dati \u00e8 cos\u00ec grande che <b>non basta la larghezza di banda di una connessione<\/b> con il DB (leggi, un processo su CPU)?..<\/p>\n<p>Oppure parte delle operazioni avviene <b>in modo asincrono<\/b> in diverse connessioni?..<\/p>\n<p>C'\u00e8 solo un'opzione qui \u2014 <b>creare temporaneamente una tabella non temporanea<\/b>. Gioco di parole, eh. Quindi:<\/p>\n<ul>\n<li>ho creato \"le mie\" tabelle con nomi massimamente casuali per non incrociarmi con nessuno<\/li>\n<li><b>Estrai<\/b>: ho caricato i dati da una fonte esterna<\/li>\n<li><b>Trasforma<\/b>: ho trasformato, compilato i campi di collegamento chiave<\/li>\n<li><b>Load<\/b>: ho trasferito i dati pronti nelle tabelle di destinazione<\/li>\n<li>ho eliminato \"le mie\" tabelle<\/li>\n<\/ul>\n<p>\nE ora \u2014 un cucchiaio di catrame. In sostanza, <b>tutta la registrazione in PostgreSQL avviene due volte<\/b> \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/postgrespro\/blog\/461523\/\">prima nel WAL<\/a><\/noindex>, poi nei corpi delle tabelle \/ indici. Tutto ci\u00f2 \u00e8 stato fatto per supportare ACID e la corretta visibilit\u00e0 dei dati tra <code>COMMIT<\/code>&#8216;incorporati e <code>ROLLBACK<\/code>&#8216;incorporati nelle transazioni.<\/p>\n<p>Ma a noi non serve! Tutto il nostro processo <b>\u00e8 andato a buon fine nel suo insieme, oppure no<\/b>. Non importa quante transazioni intermedie ci siano \u2014 non ci interessa \"continuare il processo da met\u00e0\", specialmente quando non \u00e8 chiaro dove fosse.<\/p>\n<p>A questo scopo, gli sviluppatori di PostgreSQL hanno implementato gi\u00e0 nella versione 9.1 una funzione chiamata <noindex><a rel=\"nofollow\" href=\"https:\/\/postgrespro.ru\/docs\/postgresql\/12\/sql-createtable#SQL-CREATETABLE-UNLOGGED\">tabelle non registrabili (UNLOGGED)<\/a><\/noindex>:<\/p>\n<blockquote><p>Con questa opzione, la tabella viene creata come non registrata. I dati scritti nelle tabelle non registrate non passano attraverso il log delle scritture anticipate (vedi Capitolo 29), il che significa che queste tabelle <b>funzionano molto pi\u00f9 velocemente delle normali.<\/b>. Tuttavia, non sono protette da guasti; in caso di guasto o spegnimento imprevisto del server, la tabella non registrata <b>viene automaticamente tronca.<\/b>Inoltre, il contenuto della tabella non registrata <b>non viene replicato<\/b> su server secondari. Gli indici creati per una tabella non registrata diventano automaticamente non registrati.<\/p><\/blockquote>\n<p>In breve, <b>si lavorer\u00e0 molto pi\u00f9 velocemente<\/b>, ma se il server di database \"cade\" \u2014 sar\u00e0 spiacevole. Ma quanto spesso succede e il tuo processo ETL pu\u00f2 gestirlo correttamente \"dalla met\u00e0\" dopo la \"rinascita\" del database?..<\/p>\n<p>Se non \u00e8 cos\u00ec e il caso sopra \u00e8 simile al tuo \u2014 usa <code>UNLOGGED<\/code>, ma non <b>includere mai questo attributo su tabelle reali<\/b>, i cui dati ti stanno a cuore.<\/p>\n<h3>1.3. ON COMMIT { DELETE ROWS | DROP }<\/h3>\n<p>\nQuesta costruzione consente di definire un comportamento automatico al termine della transazione quando si crea la tabella.<\/p>\n<p>Riguardo <code>ALL'IMPEGNO <b>ELIMINA<\/b><\/code> ho gi\u00e0 scritto sopra, genera <code>DROP TABLE<\/code>, ma ecco con <code>ALL'IMPEGNO <b>ELIMINA RIGHE<\/b><\/code> la situazione \u00e8 pi\u00f9 interessante: qui si genera <code>TRUNCATE TABLE<\/code>.<\/p>\n<p>Poich\u00e9 l'intera infrastruttura per la memorizzazione delle descrizioni meta delle tabelle temporanee \u00e8 esattamente la stessa di quella delle normali, <b>la continua creazione e cancellazione di tabelle temporanee porta a un forte \"gonfiore\" delle tabelle di sistema<\/b> pg_class, pg_attribute, pg_attrdef, pg_depend,\u2026<\/p>\n<p>Ora immaginate di avere un worker connesso direttamente al DB, che ogni secondo apre una nuova transazione, crea, riempie, elabora e cancella una tabella temporanea\u2026 I rifiuti nelle tabelle di sistema si accumuleranno in eccesso, causando ritardi in ogni operazione.<\/p>\n<p>In generale, non bisogna fare cos\u00ec! In questo caso \u00e8 molto pi\u00f9 efficace <code>CREATE TEMPORARY TABLE x ... ON COMMIT DELETE ROWS<\/code> portare fuori dal ciclo delle transazioni \u2014 allora all'inizio di ogni nuova transazione la tabella <b>sar\u00e0 gi\u00e0 esistente<\/b> (risparmiamo una chiamata <code>CREARE<\/code>), ma <b>sar\u00e0 vuota<\/b>, grazie a <code>TRUNCATE<\/code> (abbiamo anche risparmiato la sua chiamata) al termine della transazione precedente.<\/p>\n<h3>1.4. COME\u2026 INCLUDENDO &#8230;<\/h3>\n<p>\nHo menzionato all'inizio che uno dei casi d'uso tipici per le tabelle temporanee \u00e8 rappresentato dai vari import \u2014 e lo sviluppatore copia e incolla con fatica l'elenco dei campi della tabella di destinazione nella dichiarazione della sua tabella temporanea\u2026<\/p>\n<p>Ma la pigrizia \u00e8 il motore del progresso! Perci\u00f2 <b>creare una nuova tabella \u00abper modello\u00bb<\/b> pu\u00f2 essere molto pi\u00f9 semplice:<\/p>\n<pre><code class=\"sql\">CREATE TEMPORARY TABLE import_table(\n  LIKE target_table\n);<\/code><\/pre>\n<p>\nPoich\u00e9 si possono generare molteplici dati in questa tabella, le ricerche su di essa non saranno affatto veloci. Ma a questo si pu\u00f2 porre rimedio con le tradizionali index! E, s\u00ec, <b>anche la tabella temporanea pu\u00f2 avere indici<\/b>.<\/p>\n<p>Poich\u00e9, spesso, gli indici necessari coincidono con quelli della tabella di destinazione, si pu\u00f2 semplicemente scrivere <code>SIMILE target_table <b>INCLUDENDO GLI INDICI<\/b><\/code>.<\/p>\n<p>Se ti servono anche i <code>DEFAULT<\/code>-valori (per esempio, per riempire i valori della chiave primaria), puoi utilizzare <code>SIMILE target_table <b>INCLUDENDO PREDEFINITI<\/b><\/code>. Oppure semplicemente \u2014 <code>SIMILE target_table <b>INCLUSO TUTTO<\/b><\/code> \u2014 copier\u00e0 i default, gli indici, i vincoli,\u2026<\/p>\n<p>Ma qui bisogna capire che se hai creato <b>la tabella di importazione direttamente con gli indici, i dati ci metteranno pi\u00f9 tempo a essere caricati<\/b>, rispetto a caricarli prima e poi applicare gli indici \u2014 guarda come fa <noindex><a rel=\"nofollow\" href=\"https:\/\/postgrespro.ru\/docs\/postgresql\/12\/app-pgdump\">pg_dump<\/a><\/noindex>.<\/p>\n<p>In generale, <noindex><a rel=\"nofollow\" href=\"https:\/\/postgrespro.ru\/docs\/postgresql\/12\/sql-createtable\">RTFM<\/a><\/noindex>!<\/p>\n<h2>2. Come scrivere?<\/h2>\n<p>\nDico semplicemente \u2014 usa <code><noindex><a rel=\"nofollow\" href=\"https:\/\/postgrespro.ru\/docs\/postgresql\/12\/sql-copy\">COPY<\/a><\/noindex><\/code>-stream invece di \u00ablotto\u00bb <code>INSERT<\/code>, <noindex><a rel=\"nofollow\" href=\"https:\/\/www.citusdata.com\/blog\/2017\/11\/08\/faster-bulk-loading-in-postgresql-with-copy\/\">velocizzazione di diversi ordini<\/a><\/noindex>. Puoi anche farlo direttamente da un file preformattato.<\/p>\n<h2>3. Come elaborare?<\/h2>\n<p>\nQuindi, supponiamo che il nostro input sia pi\u00f9 o meno cos\u00ec:<\/p>\n<ul>\n<li>Hai una tabella con i dati dei clienti su <b>1M di record<\/b><\/li>\n<li>ogni giorno il client ti invia un nuovo <b>profilo completo<\/b><\/li>\n<li>dalla tua esperienza sai che, di volta in volta <b>cambiano non pi\u00f9 di 10K record<\/b><\/li>\n<\/ul>\n<p>\nUn esempio classico di una tale situazione \u00e8 <noindex><a rel=\"nofollow\" href=\"https:\/\/www.gnivc.ru\/technical_support\/classifiers_reference\/kladr\/\">la base KLDAR<\/a><\/noindex> ci sono molti indirizzi, ma in ogni esportazione settimanale le modifiche (rinominazione dei comuni, unione delle strade, apparizione di nuovi edifici) sono davvero poche anche su scala nazionale.<\/p>\n<h3>3.1. Algoritmo di sincronizzazione completa<\/h3>\n<p>\nPer semplicit\u00e0, supponiamo che non sia necessario neanche ristrutturare i dati \u2014 basta portare la tabella nel formato corretto, ovvero:<\/p>\n<ul>\n<li><b>eliminare<\/b> tutto ci\u00f2 che non esiste pi\u00f9<\/li>\n<li><b>aggiornare<\/b> tutto ci\u00f2 che c'era gi\u00e0 e deve essere aggiornato<\/li>\n<li><b>inserire<\/b> tutto ci\u00f2 che non esisteva ancora<\/li>\n<\/ul>\n<p>\nPerch\u00e9 dovresti fare le operazioni in questo ordine? Perch\u00e9 in questo modo la dimensione della tabella crescer\u00e0 al minimo (<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/tensor\/blog\/491366\/\">ricorda l'MVCC!<\/a><\/noindex>).<\/p>\n<h4>DELETE FROM dst<\/h4>\n<p>\nNo, certo, si possono fare solo due operazioni:<\/p>\n<ul>\n<li><b>eliminare<\/b> (<code>DELETE<\/code>) in realt\u00e0 tutto<\/li>\n<li><b>inserire<\/b> tutto dal nuovo profilo<\/li>\n<\/ul>\n<p>\nMa grazie all'MVCC, <b>la dimensione della tabella aumenter\u00e0 esattamente del doppio<\/b>! Ottenere +1M di profili di record nella tabella a causa dell'aggiornamento di 10K \u2014 \u00e8 un'eccesso piuttosto notevole...<\/p>\n<h4>TRUNCATE dst<\/h4>\n<p>\nUn sviluppatore pi\u00f9 esperto sa che \u00e8 possibile pulire l'intera tabella a un costo relativamente basso:<\/p>\n<ul>\n<li><b>pulire<\/b> (<code>TRUNCATE<\/code>) l'intera tabella<\/li>\n<li><b>inserire<\/b> tutto dal nuovo profilo<\/li>\n<\/ul>\n<p>\nIl metodo \u00e8 efficace, <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/tensor\/blog\/481866\/\">a volte \u00e8 del tutto applicabile<\/a><\/noindex>, ma c'\u00e8 un problema\u2026 Inserire 1M di record ci vorr\u00e0 un bel po', quindi non possiamo permetterci di lasciare la tabella vuota per tutto questo tempo (come accadr\u00e0 senza racchiudere in un'unica transazione).<\/p>\n<p>E quindi:<\/p>\n<ul>\n<li>comincia <b>una transazione lunga<\/b><\/li>\n<li><code>TRUNCATE<\/code> impone <b>AccessExclusive<\/b>-lock<\/li>\n<li>mentre facciamo l'inserimento, tutti gli altri nel frattempo <b>non possono neppure <code>SELECT<\/code><\/b><\/li>\n<\/ul>\n<p>\nNon sembra andare bene\u2026<\/p>\n<h4>ALTER TABLE\u2026 RINOMINA\u2026 \/ ELIMINA TABELLA &#8230;<\/h4>\n<p>\nCome alternativa, caricare tutto in una nuova tabella separata e poi semplicemente rinominare in quella vecchia. Ci sono un paio di fastidiosi dettagli:<\/p>\n<ul>\n<li>anche questo <b>AccessExclusive<\/b>, anche se richiede notevolmente meno tempo<\/li>\n<li>vengono annullati tutti i piani di query\/statistiche di questa tabella, <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/tensor\/blog\/479656\/\">bisogna eseguire ANALYZE<\/a><\/noindex><\/li>\n<li><b>tutti i vincoli esterni<\/b> (FK) sulla tabella<\/li>\n<\/ul>\n<p>\nC'era una patch WIP da Simon Riggs, che proponeva di fare <code>una operazione ALTER<\/code>per sostituire il corpo della tabella a livello di file, senza toccare le statistiche e i FK, ma non raggiunse il quorum.<\/p>\n<h4>DELETE, UPDATE, INSERT<\/h4>\n<p>\nQuindi, ci fermiamo sulla soluzione non bloccante tra le tre operazioni. Quasi tre... Come possiamo farlo nel modo pi\u00f9 efficace?<\/p>\n<pre><code class=\"sql\">-- tutto viene fatto nell'ambito di una transazione, affinch\u00e9 nessuno veda stati \"intermedi\"\nBEGIN;\n\n-- creiamo una tabella temporanea con i dati importati\nCREATE TEMPORARY TABLE tmp(\n  LIKE dst INCLUDING INDEXES -- per somiglianza, insieme agli indici\n) ON COMMIT DROP; -- al di fuori della transazione non ci serve\n\n-- rapidamente importiamo il nuovo set attraverso COPY\nCOPY tmp FROM STDIN;\n-- ...\n-- .\n\n-- eliminiamo i mancanti\nDELETE FROM\n  dst D\nUSING\n  dst X\nLEFT JOIN\n  tmp Y\n    USING(pk1, pk2) -- campi chiave primaria\nWHERE\n  (D.pk1, D.pk2) = (X.pk1, X.pk2) AND\n  Y IS NOT DISTINCT FROM NULL; -- \"anti-join\"\n\n-- aggiorniamo i rimanenti\nUPDATE\n  dst D\nSET\n  (f1, f2, f3) = (T.f1, T.f2, T.f3)\nFROM\n  tmp T\nWHERE\n  (D.pk1, D.pk2) = (T.pk1, T.pk2) AND\n  (D.f1, D.f2, D.f3) IS DISTINCT FROM (T.f1, T.f2, T.f3); -- non \u00e8 necessario aggiornare i corrispondenti\n\n-- inseriamo i mancanti\nINSERT INTO\n  dst\nSELECT\n  T.*\nFROM\n  tmp T\nLEFT JOIN\n  dst D\n    USING(pk1, pk2)\nWHERE\n  D IS NOT DISTINCT FROM NULL;\n\nCOMMIT;\n<\/code><\/pre>\n<p><\/p>\n<h3>3.2. Post-elaborazione dell'importazione<\/h3>\n<p>\nNello stesso KADRE, tutte le registrazioni modificate devono essere ulteriormente elaborate \u2014 normalizzate, estratte le parole chiave, convertite nelle strutture necessarie. Ma come si fa a sapere \u2014 <b>cosa sia stato esattamente modificato<\/b>, senza complicare il codice di sincronizzazione, idealmente, non toccandolo affatto?<\/p>\n<p>Se il processo di scrittura durante la sincronizzazione \u00e8 esclusivo per il vostro processo, si pu\u00f2 utilizzare un trigger che raccoglier\u00e0 tutte le modifiche per noi:<\/p>\n<pre><code class=\"sql\">-- tabelle di destinazione\nCREATE TABLE kladr(...);\nCREATE TABLE kladr_house(...);\n\n-- tabelle con la cronologia delle modifiche\nCREATE TABLE kladr$log(\n  ro kladr, -- qui si trovano le immagini intere dei record vecchi\/nuovi\n  rn kladr\n);\n\nCREATE TABLE kladr_house$log(\n  ro kladr_house,\n  rn kladr_house\n);\n\n-- funzione generale di registrazione delle modifiche\nCREATE OR REPLACE FUNCTION diff$log() RETURNS trigger AS $$\nDECLARE\n  dst varchar = TG_TABLE_NAME || '$log';\n  stmt text = '';\nBEGIN\n  -- controlliamo la necessit\u00e0 di registrare durante l'aggiornamento di un record\n  IF TG_OP = 'UPDATE' THEN\n    IF NEW IS NOT DISTINCT FROM OLD THEN\n      RETURN NEW;\n    END IF;\n  END IF;\n  -- creiamo un record di log\n  stmt = 'INSERT INTO ' || dst::text || '(ro,rn)VALUES(';\n  CASE TG_OP\n    WHEN 'INSERT' THEN\n      EXECUTE stmt || 'NULL,$1)' USING NEW;\n    WHEN 'UPDATE' THEN\n      EXECUTE stmt || '$1,$2)' USING OLD, NEW;\n    WHEN 'DELETE' THEN\n      EXECUTE stmt || '$1,NULL)' USING OLD;\n  END CASE;\n  RETURN NEW;\nEND;\n$$ LANGUAGE plpgsql;\n<\/code><\/pre>\n<p>\nOra possiamo applicare i trigger prima dell'inizio della sincronizzazione (o abilitarli tramite <code>ALTER TABLE ... ENABLE TRIGGER ...<\/code>):<\/p>\n<pre><code class=\"sql\">CREATE TRIGGER log\n  AFTER INSERT OR UPDATE OR DELETE\n  ON kladr\n    FOR EACH ROW\n      EXECUTE PROCEDURE diff$log();\n\nCREATE TRIGGER log\n  AFTER INSERT OR UPDATE OR DELETE\n  ON kladr_house\n    FOR EACH ROW\n      EXECUTE PROCEDURE diff$log();\n<\/code><\/pre>\n<p>\nE poi possiamo estrarre tranquillamente tutte le modifiche necessarie dalle tabelle di log e passarle attraverso ulteriori elaboratori.<\/p>\n<h3>3.3. Importazione di insiemi di dati correlati<\/h3>\n<p>\nIn precedenza abbiamo esaminato i casi in cui le strutture dati della sorgente e del destinatario sono coincidenti. Ma cosa fare se l'esportazione da un sistema esterno ha un formato diverso dalla struttura di archiviazione nel nostro database?<\/p>\n<p>Prendiamo come esempio la conservazione dei clienti e delle relative fatture, classico caso di \"molti-a-uno\":<\/p>\n<pre><code class=\"sql\">CREATE TABLE client(\n  client_id\n    serial\n      PRIMARY KEY\n, inn\n    varchar\n      UNIQUE\n, name\n    varchar\n);\n\nCREATE TABLE invoice(\n  invoice_id\n    serial\n      PRIMARY KEY\n, client_id\n    integer\n      REFERENCES client(client_id)\n, number\n    varchar\n, dt\n    date\n, sum\n    numeric(32,2)\n);<\/code><\/pre>\n<p>\nMa ecco che l'esportazione da una fonte esterna arriva a noi in forma di \"tutto in uno\":<\/p>\n<pre><code class=\"sql\">CREATE TEMPORARY TABLE invoice_import(\n  client_inn\n    varchar\n, client_name\n    varchar\n, invoice_number\n    varchar\n, invoice_dt\n    date\n, invoice_sum\n    numeric(32,2)\n);<\/code><\/pre>\n<p>\n\u00c8 evidente che i dati sui clienti possono essere duplicati in questo caso, e la registrazione principale \u00e8 \"fattura\":<\/p>\n<pre><code class=\"plaintext\">0123456789;Vasya;A-01;2020-03-16;1000.00\n9876543210;Petya;A-02;2020-03-16;666.00\n0123456789;Vasya;B-03;2020-03-16;9999.00\n<\/code><\/pre>\n<p>\nPer il modello, inseriamo semplicemente i nostri dati di test, ma ricordiamo \u2014 <code>COPY<\/code> \u00e8 pi\u00f9 efficiente!<\/p>\n<pre><code class=\"sql\">INSERT INTO invoice_import\nVALUES\n  ('0123456789', 'Vasja', 'A-01', '2020-03-16', 1000.00)\n, ('9876543210', 'Petja', 'A-02', '2020-03-16', 666.00)\n, ('0123456789', 'Vasja', 'B-03', '2020-03-16', 9999.00);<\/code><\/pre>\n<p>\nPrima di tutto, identifichiamo i 'tagli' a cui i nostri 'fatti' si riferiscono. Nel nostro caso, le fatture si riferiscono ai clienti:<\/p>\n<pre><code class=\"sql\">CREATE TEMPORARY TABLE client_import AS\nSELECT DISTINCT ON(client_inn)\n-- pu\u00f2 essere semplicemente SELECT DISTINCT, se i dati sono noto per essere non contraddittori\n  client_inn inn\n, client_name \"name\"\nFROM\n  invoice_import;<\/code><\/pre>\n<p>\nPer collegare correttamente le fatture agli ID dei clienti, dobbiamo prima ottenere o generare questi identificatori. Aggiungiamo i campi per essi:<\/p>\n<pre><code class=\"sql\">ALTER TABLE invoice_import ADD COLUMN client_id integer;\nALTER TABLE client_import ADD COLUMN client_id integer;<\/code><\/pre>\n<p>\nUtilizzeremo il metodo di sincronizzazione descritto sopra con una leggera modifica: non aggiorneremo n\u00e9 cancelleremo nulla nella tabella di destinazione, poich\u00e9 l'importazione dei clienti \u00e8 'append-only':<\/p>\n<pre><code class=\"sql\">-- impostiamo nella tabella di importazione l'ID delle registrazioni esistenti\nUPDATE\n  client_import T\nSET\n  client_id = D.client_id\nFROM\n  client D\nWHERE\n  T.inn = D.inn; -- chiave unica\n\n-- inseriamo le registrazioni mancanti e impostiamo i loro ID\nWITH ins AS (\n  INSERT INTO client(\n    inn\n  , name\n  )\n  SELECT\n    inn\n  , name\n  FROM\n    client_import\n  WHERE\n    client_id IS NULL -- se l'ID non \u00e8 stato impostato\n  RETURNING *\n)\nUPDATE\n  client_import T\nSET\n  client_id = D.client_id\nFROM\n  ins D\nWHERE\n  T.inn = D.inn; -- chiave unica\n\n-- impostiamo l'ID dei clienti per le registrazioni delle fatture\nUPDATE\n  invoice_import T\nSET\n  client_id = D.client_id\nFROM\n  client_import D\nWHERE\n  T.client_inn = D.inn; -- chiave applicativa\n<\/code><\/pre>\n<p>\nIn sostanza, tutto \u2014 in <code>invoice_import<\/code> ora abbiamo popolato il campo di collegamento <code>client_id<\/code>, con cui inseriremo la fattura.<br \/>\n<br \/>Fonte: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/tensor\/blog\/492464\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u0438 \u0441\u043b\u043e\u0436\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043d\u0430\u0431\u043e\u0440\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445 (\u0440\u0430\u0437\u043d\u044b\u0435 ETL-\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b: \u0438\u043c\u043f\u043e\u0440\u0442\u044b, \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0438 \u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0441 \u0432\u043d\u0435\u0448\u043d\u0438\u043c \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u043c) \u0447\u0430\u0441\u0442\u043e \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u00ab\u0437\u0430\u043f\u043e\u043c\u043d\u0438\u0442\u044c\u00bb, \u0438 \u0441\u0440\u0430\u0437\u0443 \u0431\u044b\u0441\u0442\u0440\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \u043e\u0431\u044a\u0435\u043c\u043d\u043e\u0435. \u0422\u0438\u043f\u043e\u0432\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0440\u043e\u0434\u0430 \u0437\u0432\u0443\u0447\u0438\u0442 \u043e\u0431\u044b\u0447\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a: \u00ab\u0412\u043e\u0442 \u0442\u0443\u0442 \u0431\u0443\u0445\u0433\u0430\u043b\u0442\u0435\u0440\u0438\u044f \u0432\u044b\u0433\u0440\u0443\u0437\u0438\u043b\u0430 \u0438\u0437 \u043a\u043b\u0438\u0435\u043d\u0442-\u0431\u0430\u043d\u043a\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u043f\u043e\u0441\u0442\u0443\u043f\u0438\u0432\u0448\u0438\u0435 \u043e\u043f\u043b\u0430\u0442\u044b, \u043d\u0430\u0434\u043e \u0438\u0445 \u0431\u044b\u0441\u0442\u0440\u0435\u043d\u044c\u043a\u043e \u0432\u043a\u0430\u0447\u0430\u0442\u044c \u043d\u0430 \u0441\u0430\u0439\u0442 \u0438 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u0442\u044c \u043a \u0441\u0447\u0435\u0442\u0430\u043c\u00bb \u041d\u043e \u043a\u043e\u0433\u0434\u0430 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":74954,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-74953","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 4.9.10 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041f\u0440\u0438 \u0441\u043b\u043e\u0436\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043d\u0430\u0431\u043e\u0440\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445 (\u0440\u0430\u0437\u043d\u044b\u0435 ETL-\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b: \u0438\u043c\u043f\u043e\u0440\u0442\u044b, \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0438 \u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0441 \u0432\u043d\u0435\u0448\u043d\u0438\u043c \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u043c) \u0447\u0430\u0441\u0442\u043e \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u00ab\u0437\u0430\u043f\u043e\u043c\u043d\u0438\u0442\u044c\u00bb, \u0438 \u0441\u0440\u0430\u0437\u0443 \u0431\u044b\u0441\u0442\u0440\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \u043e\u0431\u044a\u0435\u043c\u043d\u043e\u0435. \u0422\u0438\u043f\u043e\u0432\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0440\u043e\u0434\u0430 \u0437\u0432\u0443\u0447\u0438\u0442 \u043e\u0431\u044b\u0447\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a: \u00ab\u0412\u043e\u0442 \u0442\u0443\u0442 \u0431\u0443\u0445\u0433\u0430\u043b\u0442\u0435\u0440\u0438\u044f \u0432\u044b\u0433\u0440\u0443\u0437\u0438\u043b\u0430 \u0438\u0437 \u043a\u043b\u0438\u0435\u043d\u0442-\u0431\u0430\u043d\u043a\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u043f\u043e\u0441\u0442\u0443\u043f\u0438\u0432\u0448\u0438\u0435 \u043e\u043f\u043b\u0430\u0442\u044b, \u043d\u0430\u0434\u043e \u0438\u0445 \u0431\u044b\u0441\u0442\u0440\u0435\u043d\u044c\u043a\u043e \u0432\u043a\u0430\u0447\u0430\u0442\u044c \u043d\u0430 \u0441\u0430\u0439\u0442 \u0438 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u0442\u044c \u043a \u0441\u0447\u0435\u0442\u0430\u043c\u00bb \u041d\u043e \u043a\u043e\u0433\u0434\u0430\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/dba-gramotno-organizovyvaem-sinhronizaczii-i-importy\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 4.9.10\" \/>\n\t\t<meta property=\"og:locale\" content=\"it_IT\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47DBA: \u0433\u0440\u0430\u043c\u043e\u0442\u043d\u043e \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0435\u043c \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u0438\u043c\u043f\u043e\u0440\u0442\u044b | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041f\u0440\u0438 \u0441\u043b\u043e\u0436\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043d\u0430\u0431\u043e\u0440\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445 (\u0440\u0430\u0437\u043d\u044b\u0435 ETL-\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b: \u0438\u043c\u043f\u043e\u0440\u0442\u044b, \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0438 \u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0441 \u0432\u043d\u0435\u0448\u043d\u0438\u043c \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u043c) \u0447\u0430\u0441\u0442\u043e \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u00ab\u0437\u0430\u043f\u043e\u043c\u043d\u0438\u0442\u044c\u00bb, \u0438 \u0441\u0440\u0430\u0437\u0443 \u0431\u044b\u0441\u0442\u0440\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \u043e\u0431\u044a\u0435\u043c\u043d\u043e\u0435. \u0422\u0438\u043f\u043e\u0432\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0440\u043e\u0434\u0430 \u0437\u0432\u0443\u0447\u0438\u0442 \u043e\u0431\u044b\u0447\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a: \u00ab\u0412\u043e\u0442 \u0442\u0443\u0442 \u0431\u0443\u0445\u0433\u0430\u043b\u0442\u0435\u0440\u0438\u044f \u0432\u044b\u0433\u0440\u0443\u0437\u0438\u043b\u0430 \u0438\u0437 \u043a\u043b\u0438\u0435\u043d\u0442-\u0431\u0430\u043d\u043a\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u043f\u043e\u0441\u0442\u0443\u043f\u0438\u0432\u0448\u0438\u0435 \u043e\u043f\u043b\u0430\u0442\u044b, \u043d\u0430\u0434\u043e \u0438\u0445 \u0431\u044b\u0441\u0442\u0440\u0435\u043d\u044c\u043a\u043e \u0432\u043a\u0430\u0447\u0430\u0442\u044c \u043d\u0430 \u0441\u0430\u0439\u0442 \u0438 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u0442\u044c \u043a \u0441\u0447\u0435\u0442\u0430\u043c\u00bb \u041d\u043e \u043a\u043e\u0433\u0434\u0430\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/dba-gramotno-organizovyvaem-sinhronizaczii-i-importy\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-03-22T05:42:22+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-03-22T05:42:22+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47DBA: organizziamo le sincronizzazioni e gli import con competenza | ProHoster","description":"Nella gestione complessa di grandi set di dati (vari processi ETL: importazioni, conversions e sincronizzazioni con fonti esterne) si presenta spesso la necessit\u00e0 di \"memorizzare\" temporaneamente e rapidamente elaborare qualcosa di voluminoso. Un compito tipico di questo tipo suona di solito pi\u00f9 o meno cos\u00ec: \"Qui la contabilit\u00e0 ha estratto dal client-banca gli ultimi pagamenti ricevuti, dobbiamo caricarli rapidamente sul sito e collegarli alle fatture\" Ma quando","canonical_url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/dba-gramotno-organizovyvaem-sinhronizaczii-i-importy","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"it_IT","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47DBA: \u0433\u0440\u0430\u043c\u043e\u0442\u043d\u043e \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0435\u043c \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u0438\u043c\u043f\u043e\u0440\u0442\u044b | ProHoster","og:description":"\u041f\u0440\u0438 \u0441\u043b\u043e\u0436\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043d\u0430\u0431\u043e\u0440\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445 (\u0440\u0430\u0437\u043d\u044b\u0435 ETL-\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b: \u0438\u043c\u043f\u043e\u0440\u0442\u044b, \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0438 \u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0441 \u0432\u043d\u0435\u0448\u043d\u0438\u043c \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u043c) \u0447\u0430\u0441\u0442\u043e \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u00ab\u0437\u0430\u043f\u043e\u043c\u043d\u0438\u0442\u044c\u00bb, \u0438 \u0441\u0440\u0430\u0437\u0443 \u0431\u044b\u0441\u0442\u0440\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \u043e\u0431\u044a\u0435\u043c\u043d\u043e\u0435. \u0422\u0438\u043f\u043e\u0432\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0440\u043e\u0434\u0430 \u0437\u0432\u0443\u0447\u0438\u0442 \u043e\u0431\u044b\u0447\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a: \u00ab\u0412\u043e\u0442 \u0442\u0443\u0442 \u0431\u0443\u0445\u0433\u0430\u043b\u0442\u0435\u0440\u0438\u044f \u0432\u044b\u0433\u0440\u0443\u0437\u0438\u043b\u0430 \u0438\u0437 \u043a\u043b\u0438\u0435\u043d\u0442-\u0431\u0430\u043d\u043a\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u043f\u043e\u0441\u0442\u0443\u043f\u0438\u0432\u0448\u0438\u0435 \u043e\u043f\u043b\u0430\u0442\u044b, \u043d\u0430\u0434\u043e \u0438\u0445 \u0431\u044b\u0441\u0442\u0440\u0435\u043d\u044c\u043a\u043e \u0432\u043a\u0430\u0447\u0430\u0442\u044c \u043d\u0430 \u0441\u0430\u0439\u0442 \u0438 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u0442\u044c \u043a \u0441\u0447\u0435\u0442\u0430\u043c\u00bb \u041d\u043e \u043a\u043e\u0433\u0434\u0430","og:url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/dba-gramotno-organizovyvaem-sinhronizaczii-i-importy","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-03-22T05:42:22+00:00","article:modified_time":"2020-03-22T05:42:22+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"74953","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 18:04:26","updated":"2022-09-30 13:25:20"},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/74953","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/comments?post=74953"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/74953\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media\/74954"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media?parent=74953"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/categories?post=74953"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/tags?post=74953"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}