{"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\/sl\/blog\/administrirovanie\/dba-gramotno-organizovyvaem-sinhronizaczii-i-importy","title":{"rendered":"DBA: uspe\u0161no organiziramo sinhronizacije in uvoze","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Pri kompleksni obdelavi velikih naborov podatkov (razli\u010dne <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/ETL\">ETL procese<\/a><\/noindex>: uvozi, konverzije in sinhronizacije z zunanjim virom) pogosto nastane potreba <b>za za\u010dasno \"zapomnitev\" in hitro obdelavo<\/b> nekaj obse\u017enega.<\/p>\n<p>Tipi\u010dna naloga tovrstne narave se obi\u010dajno sli\u0161i takole: <i>\"Tukaj <noindex><a rel=\"nofollow\" href=\"https:\/\/sbis.ru\/accounting\">ra\u010dunovodstvo je izvo\u017eilo iz spletne banke<\/a><\/noindex> zadnja prejeta pla\u010dila, treba jih je hitro prenesti na splet in povezati z ra\u010duni\"<\/i><\/p>\n<p>\u041d\u043e \u043a\u043e\u0433\u0434\u0430 \u043e\u0431\u044a\u0435\u043c \u044d\u0442\u043e\u0433\u043e \u00ab\u0447\u0435\u0433\u043e-\u0442\u043e\u00bb \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u0438\u0437\u043c\u0435\u0440\u044f\u0442\u044c\u0441\u044f \u0441\u043e\u0442\u043d\u044f\u043c\u0438 \u043c\u0435\u0433\u0430\u0431\u0430\u0439\u0442, \u0430 \u0441\u0435\u0440\u0432\u0438\u0441 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0431\u0430\u0437\u043e\u0439 \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 24&#215;7, \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e side-\u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u043f\u043e\u0440\u0442\u0438\u0442\u044c \u0432\u0430\u043c \u0436\u0438\u0437\u043d\u044c.<br \/>\n<img decoding=\"async\" alt=\"DBA: uspe\u0161no organiziramo sinhronizacije in uvoze\" src=\"\/wp-content\/uploads\/2020\/03\/f74afb2cd6f5f8de26a0932166933c95.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDa bi se z njimi spoprijeli v PostgreSQL (pa tudi ne samo v njem), lahko uporabite nekatere mo\u017enosti za optimizacijo, ki bodo omogo\u010dile hitrej\u0161o obdelavo z manj\u0161im porabo virov.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>1. Kam nalivati?<\/h2>\n<p>\nNajprej ugotovimo, kam lahko nalo\u017eimo podatke, ki jih \u017eelimo \"obdelati\".<\/p>\n<h3>1.1. Za\u010dasne tabele (TEMPORARY TABLE)<\/h3>\n<p>\nNa splo\u0161no so za PostgreSQL za\u010dasne tabele enake kot katere koli druge. Zato so napa\u010dna prepri\u010danja, kot so <i><b>\"vse je shranjeno samo v pomnilniku, ki se lahko kon\u010da\"<\/b><\/i>. Vendar pa obstajajo tudi nekatere bistvene razlike.<\/p>\n<h4>Lastni \"imenski prostor\" za vsako povezavo na BDP<\/h4>\n<p>\n\u010ce posku\u0161ata dve povezavi hkrati izvesti <code>CREATE TABLE x<\/code>, bo nekdo nujno naletel <b>na napako o uni\u010denosti<\/b> BDP objektov.<\/p>\n<p>\u010ce pa bosta oba posku\u0161ala izvesti <code>CREATE <b>ZA\u010cASNO<\/b> TABELA x<\/code>, bosta oba to normalno naredila, in vsak bo dobil <b>svoj primer<\/b> tabele. In med njima ne bo ni\u010d skupnega.<\/p>\n<h4>\"Samouni\u010denje\" ob odjavi<\/h4>\n<p>\nOb zapiranju povezave se vse za\u010dasne tabele samodejno izbri\u0161ejo, zato \"ro\u010dnega\" izvajanja <code>DROP TABLE x<\/code> ni nobenega smisla, razen ...<\/p>\n<p>\u010ce delate preko <b>pgbouncer v na\u010dinu transakcij<\/b>, baza \u0161e vedno misli, da je ta povezava \u0161e aktivna, in v njej ta za\u010dasna tabela \u0161e vedno obstaja.<\/p>\n<p>Zato bo poskus ponovnega ustvarjanja iz druge povezave do pgbouncer pripeljal do napake. Toda to lahko obidete, tako da uporabite <code>USTVARI ZA\u010cASNO TABELO <b>\u010cE NE OBSTAJA<\/b> x<\/code>.<\/p>\n<p>Toda bolje je, da tega ne delate, ker lahko \"nenadoma\" naletite na podatke, ki so ostali od \"prej\u0161njega lastnika\". Namesto tega je veliko bolje prebrati navodila in videti, da ob ustvarjanju tabele obstaja mo\u017enost, da dodate <code>NA ZAVEZI <b>DROP<\/b><\/code> \u2014 to pomeni, da bo tabela samodejno izbrisana ob koncu transakcije.<\/p>\n<h4>Nerepliciranje<\/h4>\n<p>\nZaradi pripadnosti samo dolo\u010denemu povezovanju se za\u010dasne tabele ne replicirajo. Vendar <b>to odstrani potrebo po dvojni zapisovanju podatkov<\/b> v heap + WAL, zato je INSERT\/UPDATE\/DELETE v njih bistveno hitrej\u0161i.<\/p>\n<p>Toda ker je za\u010dasna tabela vseeno 'skoraj obi\u010dajna', je tudi na replikaciji ni mogo\u010de ustvariti. Vsaj zaenkrat ne, \u010deprav ustrezen popravek \u017ee dolgo \u010dasa kro\u017ei.<\/p>\n<h3>1.2. Nezapisljive tabele (UNLOGGED TABLE)<\/h3>\n<p>\nToda kaj storiti, na primer, \u010de imate nek obse\u017een ETL-proces, ki ga ne morete izvesti v okviru ene transakcije, in imate <b>pgbouncer v na\u010dinu transakcij<\/b>?..<\/p>\n<p>Ali je tok podatkov tako velik, da <b>ni dovolj pasovne \u0161irine enega povezovanja<\/b> z DB (beri, enega procesa na CPU)?..<\/p>\n<p>Ali del operacij poteka <b>asinhrono<\/b> v razli\u010dnih povezavah?..<\/p>\n<p>Tu je le ena re\u0161itev \u2014 <b>za\u010dasno ustvariti ne-zaklju\u010deno tabelo<\/b>. Igra besed, da. To pomeni:<\/p>\n<ul>\n<li>ustvaril sem 'svoje' tabele z maksimalno naklju\u010dnimi imeni, da ne bi naletel na koga drugega<\/li>\n<li><b>Extract<\/b>: nalil sem podatke iz zunanjega vira vanje<\/li>\n<li><b>Transform<\/b>: jih pretvoril, izpolnil klju\u010dna povezovalna polja<\/li>\n<li><b>U\u010ditavanje<\/b>: prelil pripravljene podatke v ciljna tabela<\/li>\n<li>sem izbrisal 'svoje' tabele<\/li>\n<\/ul>\n<p>\nIn zdaj \u2014 \u017elica katrana. V bistvu, <b>vse zajemanje v PostgreSQL poteka dvakrat<\/b> \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/postgrespro\/blog\/461523\/\">prvi\u010d v WAL<\/a><\/noindex>, nato pa \u017ee v telesa tabel\/indeksov. Vse to je narejeno za podporo ACID in pravilni vidljivosti podatkov med <code>COMMIT<\/code>&#8216;\u043d\u0443\u0442\u044b\u043c\u0438 \u0438 <code>ROLLBACK<\/code>&#8216;\u043d\u0443\u0442\u044b\u043c\u0438 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f\u043c\u0438.<\/p>\n<p>Toda tega mi ne potrebujemo! Na\u0161 celoten proces <b>ali uspe\u0161no uspe, ali pa ne<\/b>. Ni pomembno, koliko bo v njem vmesnih transakcij \u2014 ni nam zanimivo 'nadaljevati postopek sredi', \u0161e posebej, ko ni jasno, kje je bila.<\/p>\n<p>Zato so razvijalci PostgreSQL v razli\u010dici 9.1 uvedli tak\u0161no stvar kot <noindex><a rel=\"nofollow\" href=\"https:\/\/postgrespro.ru\/docs\/postgresql\/12\/sql-createtable#SQL-CREATETABLE-UNLOGGED\">nezapisljive (UNLOGGED) tabele.<\/a><\/noindex>:<\/p>\n<blockquote><p>S tem navedkom se tabela ustvari kot nezapisljiva. Podatki, zapisani v nezapisljive tabele, ne prehajajo skozi predizpisni dnevnik (glej Glavo 29), zaradi \u010desar te tabele <b>delujejo precej hitreje od obi\u010dajnih.<\/b>Vendar pa niso za\u0161\u010ditene pred napako; pri izpadu ali nenadnem izklopu stre\u017enika se nezapisljiva tabela <b>samodejno izre\u017ee.<\/b>Poleg tega se vsebina nezapisljive tabele <b>ne replicira.<\/b> na vodene stre\u017enike. Vse indekse, ustvarjene za nebele\u017eene tabele, se samodejno pretvorijo v nebele\u017eene.<\/p><\/blockquote>\n<p>Na kratko, <b>bo bistveno hitrej\u0161e<\/b>, a \u010de server baze podatkov 'pade' \u2013 bo neprijetno. Ampak, koliko pogosto se to zgodi, in ali va\u0161 ETL postopek to lahko pravilno obdeluje 's sredine' po 'o\u017eivitvi' baze podatkov?..<\/p>\n<p>\u010ce ni, in je zgornji primer podoben va\u0161emu \u2013 uporabite <code>UNLOGGED<\/code>, a nikoli <b>ne vklju\u010dite tega atributa na pravih tabelah<\/b>, katerih podatki so vam dragi.<\/p>\n<h3>1.3. ON COMMIT { DELETE ROWS | DROP }<\/h3>\n<p>\nTa konstrukcija omogo\u010da, da ob ustvarjanju tabele dolo\u010dite samodejno vedenje ob zaklju\u010dku transakcije.<\/p>\n<p>O <code>NA ZAVEZI <b>DROP<\/b><\/code> \u017ee sem napisal zgoraj, generira <code>DROP TABLE<\/code>, a tukaj je <code>NA ZAVEZI <b>IZBRI\u0160I VRSTE<\/b><\/code> situacija zanimivej\u0161a \u2013 tukaj se generira <code>TRUNCATE TABLE<\/code>.<\/p>\n<p>Ker je celotna infrastruktura shranjevanja metaopisov za\u010dasne tabele enaka kot pri obi\u010dajni, <b>nenehno ustvarjanje-in-brisanje za\u010dasnih tabel povzro\u010da mo\u010dno 'napihovanje' sistemskih tabel<\/b> pg_class, pg_attribute, pg_attrdef, pg_depend,\u2026<\/p>\n<p>Zdaj si predstavljajte, da imate delavca na neposredni povezavi z bazo podatkov, ki vsako sekundo odpre novo transakcijo, ustvarja, napolnjuje, obdeluje in bri\u0161e za\u010dasno tabelo\u2026 Odpadkov v sistemskih tabelah se bo nakopi\u010dilo preve\u010d, kar povzro\u010da dodatne zaostanke pri vsaki operaciji.<\/p>\n<p>Na splo\u0161no, tega ne delajte! V tem primeru je mnogo u\u010dinkoviteje <code>USTVARI ZA\u010cASNO TABLE x ... ON COMMIT DELETE ROWS<\/code> premakniti izven transakcijskega cikla \u2013 tako bodo ob za\u010detku vsake nove transakcije tabele \u017ee <b>obstajale<\/b> (prihranimo klic <code>CREATE<\/code>), ampak <b>bo prazna<\/b>, zahvaljujo\u010d <code>TRUNCATE<\/code> (tudi ta klic smo prihranili) ob zaklju\u010dku prej\u0161nje transakcije.<\/p>\n<h3>1.4. LIKE\u2026 INCLUDING &#8230;<\/h3>\n<p>\nOmenil sem na za\u010detku, da je eden od tipi\u010dnih primerov uporabe za za\u010dasne tabele \u2013 razli\u010dne vrste uvozov \u2013 in razvijalec utrujeno kopira seznam polj ciljne tabele v deklaracijo svoje za\u010dasne\u2026<\/p>\n<p>Ampak lenoba je motor napredka! Zato <b>lahko ustvarite novo tabelo 'po vzoru'<\/b> veliko preprosteje:<\/p>\n<pre><code class=\"sql\">USTVARI ZA\u010cASNO TABELO import_table(\n  LIKE target_table\n);<\/code><\/pre>\n<p>\nKer lahko v to tabelo nato vnesete precej veliko podatkov, iskanje v njej ne bo hitro. Vendar pa obstaja tradicionalna re\u0161itev \u2013 indeksi! In, da, <b>imajo tudi za\u010dasne tabele indekse<\/b>.<\/p>\n<p>Ker se pogosto potrebni indeksi ujemajo z indeksi ciljne tabele, jih lahko preprosto zapi\u0161ete <code>PODOBEN target_table <b>VKLJU\u010cNO Z INDEKSI<\/b><\/code>.<\/p>\n<p>\u010ce potrebujete \u0161e <code>DEFAULT<\/code>-vrednosti (na primer, za izpolnitev vrednosti primarnega klju\u010da), lahko uporabite <code>PODOBEN target_table <b>VKLJU\u010cUJO\u010c BAZNE NASTAVITVE<\/b><\/code>. Ali pa preprosto \u2014 <code>PODOBEN target_table <b>VKLJU\u010cUJO\u010c VSE<\/b><\/code> \u2014 kopira privzete vrednosti, indekse, omejitve,\u2026<\/p>\n<p>Ampak tukaj je treba razumeti, da \u010de ste ustvarili <b>uvozno tabelo takoj z indeksi, se bodo podatki nalagali dlje<\/b>, kot \u010de najprej vse nalo\u017eite, nato pa dodate indekse \u2014 poglejte na primer, kako to po\u010dne <noindex><a rel=\"nofollow\" href=\"https:\/\/postgrespro.ru\/docs\/postgresql\/12\/app-pgdump\">pg_dump<\/a><\/noindex>.<\/p>\n<p>Na splo\u0161no, <noindex><a rel=\"nofollow\" href=\"https:\/\/postgrespro.ru\/docs\/postgresql\/12\/sql-createtable\">RTFM<\/a><\/noindex>!<\/p>\n<h2>2. Kako pisati?<\/h2>\n<p>\nPovem preprosto \u2014 uporabite <code><noindex><a rel=\"nofollow\" href=\"https:\/\/postgrespro.ru\/docs\/postgresql\/12\/sql-copy\">COPY<\/a><\/noindex><\/code>-tok namesto \u201epaketa\u201c <code>INSERT<\/code>, <noindex><a rel=\"nofollow\" href=\"https:\/\/www.citusdata.com\/blog\/2017\/11\/08\/faster-bulk-loading-in-postgresql-with-copy\/\">pospe\u0161itev za ve\u010dkrat<\/a><\/noindex>. Lahko celo neposredno iz vnaprej oblikovane datoteke.<\/p>\n<h2>3. Kako obdelovati?<\/h2>\n<p>\nTorej, naj bo na\u0161 vhod pribli\u017eno tak\u0161en:<\/p>\n<ul>\n<li>imate v bazi shranjeno tabelo s podatki strank na <b>1M zapisov<\/b><\/li>\n<li>vsak dan vam stranka po\u0161lje nov <b>popoln \u201emodel\u201c<\/b><\/li>\n<li>po izku\u0161njah veste, da se od enega do drugega <b>spremeni najve\u010d 10K zapisov<\/b><\/li>\n<\/ul>\n<p>\nKlasi\u010den primer tak\u0161ne situacije je <noindex><a rel=\"nofollow\" href=\"https:\/\/www.gnivc.ru\/technical_support\/classifiers_reference\/kladr\/\">baza KLASR<\/a><\/noindex> \u2014 vseh naslovov je veliko, a v vsakem tedenskem izvozu sprememb (preimenovanja naselij, zdru\u017eevanje ulic, pojav novih hi\u0161) je zelo malo celo v obsegu celotne dr\u017eave.<\/p>\n<h3>3.1. Algoritem popolne sinhronizacije<\/h3>\n<p>\nZa preprostost domnevamo, da vam ni treba niti prestrukturirati podatkov \u2014 samo prilagoditi tabelo v \u017eeleno obliko, torej:<\/p>\n<ul>\n<li><b>izbrisati<\/b> vse, \u010desar \u017ee ni<\/li>\n<li><b>posodobiti<\/b> vse, kar je \u017ee bilo, in je treba posodobiti<\/li>\n<li><b>vstaviti<\/b> vse, \u010desar \u0161e ni bilo<\/li>\n<\/ul>\n<p>\nZakaj je treba operacije izvesti v tem vrstnem redu? Ker samo tako bo velikost tabele rasla minimalno (<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/tensor\/blog\/491366\/\">ne forget about MVCC!<\/a><\/noindex>).<\/p>\n<h4>DELETE FROM dst<\/h4>\n<p>\nNe, seveda lahko zado\u0161\u010da \u017ee samo dve operaciji:<\/p>\n<ul>\n<li><b>izbrisati<\/b> (<code>DELETE<\/code>) pravzaprav vse<\/li>\n<li><b>vstaviti<\/b> vse iz novega modela<\/li>\n<\/ul>\n<p>\nAmpak s tem, zahvaljujo\u010d MVCC, <b>velikost tabele se bo pove\u010dala to\u010dno dvakrat<\/b>! Pridobiti +1M modelov zapisov v tabeli zaradi posodobitve 10K \u2014 to je slaba odve\u010dnost\u2026<\/p>\n<h4>TRUNCATE dst<\/h4>\n<p>\nBolj izku\u0161en razvijalec ve, da lahko celotno tabelo \u010distimo razmeroma poceni:<\/p>\n<ul>\n<li><b>obri\u0161i<\/b> (<code>TRUNCATE<\/code>) celotno tabelo<\/li>\n<li><b>vstaviti<\/b> vse iz novega modela<\/li>\n<\/ul>\n<p>\nMetoda je u\u010dinkovita, <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/tensor\/blog\/481866\/\">v\u010dasih povsem uporabna<\/a><\/noindex>, ampak obstaja te\u017eava\u2026 Nalivanje 1M zapisov bo trajalo dolgo, zato si ne moremo privo\u0161\u010diti, da bi tabela ostala prazna ves ta \u010das (kot se bo zgodilo brez obvijanja v eno samo transakcijo).<\/p>\n<p>To pomeni:<\/p>\n<ul>\n<li>za\u010dnemo <b>dolgo transakcijo<\/b><\/li>\n<li><code>TRUNCATE<\/code> vsiljuje <b>AccessExclusive<\/b>-zaklep<\/li>\n<li>dalj \u010dasa izvajamo vstavek, vsi ostali pa v tem \u010dasu <b>ne morejo niti <code>SELECT<\/code><\/b><\/li>\n<\/ul>\n<p>\nNekaj ni v redu\u2026<\/p>\n<h4>ALTER TABLE\u2026 RENAME\u2026 \/ DROP TABLE &#8230;<\/h4>\n<p>\nAlternativa \u2014 carregar tudo em uma nova tabela separada e depois apenas renomear para o lugar da antiga. Algumas pequenas complica\u00e7\u00f5es:<\/p>\n<ul>\n<li>tamb\u00e9m isso <b>AccessExclusive<\/b>, embora significativamente menos demorado<\/li>\n<li>todos os planos de consultas\/estat\u00edsticas dessa tabela s\u00e3o redefinidos, <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/tensor\/blog\/479656\/\">precisamos executar ANALYZE<\/a><\/noindex><\/li>\n<li><b>todas as chaves estrangeiras quebram<\/b> (FK) para a tabela<\/li>\n<\/ul>\n<p>\nHouve um patch WIP de Simon Riggs, que sugeria fazer <code>ALTER<\/code>-uma opera\u00e7\u00e3o para substituir o corpo da tabela no n\u00edvel de arquivo, sem alterar as estat\u00edsticas e FK, mas n\u00e3o conseguiu reunir qu\u00f3rum.<\/p>\n<h4>DELETE, UPDATE, INSERT<\/h4>\n<p>\nAssim, ficamos com a op\u00e7\u00e3o n\u00e3o bloqueante das tr\u00eas opera\u00e7\u00f5es. Quase tr\u00eas... Como fazer isso da maneira mais eficiente?<\/p>\n<pre><code class=\"sql\">-- \u0432\u0441\u0435 \u0434\u0435\u043b\u0430\u0435\u043c \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438, \u0447\u0442\u043e\u0431\u044b \u043d\u0438\u043a\u0442\u043e \u043d\u0435 \u0432\u0438\u0434\u0435\u043b &quot;\u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0445&quot; \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439\nBEGIN;\n\n-- \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0441 \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438\nCREATE TEMPORARY TABLE tmp(\n  LIKE dst INCLUDING INDEXES -- \u043f\u043e \u043e\u0431\u0440\u0430\u0437\u0443 \u0438 \u043f\u043e\u0434\u043e\u0431\u0438\u044e, \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0438\u043d\u0434\u0435\u043a\u0441\u0430\u043c\u0438\n) ON COMMIT DROP; -- \u0437\u0430 \u0440\u0430\u043c\u043a\u0430\u043c\u0438 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 \u043e\u043d\u0430 \u043d\u0430\u043c \u043d\u0435 \u043d\u0443\u0436\u043d\u0430\n\n-- \u0431\u044b\u0441\u0442\u0440\u043e-\u0431\u044b\u0441\u0442\u0440\u043e \u0432\u043b\u0438\u0432\u0430\u0435\u043c \u043d\u043e\u0432\u044b\u0439 \u043e\u0431\u0440\u0430\u0437 \u0447\u0435\u0440\u0435\u0437 COPY\nCOPY tmp FROM STDIN;\n-- ...\n-- .\n\n-- \u0443\u0434\u0430\u043b\u044f\u0435\u043c \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435\nDELETE FROM\n  dst D\nUSING\n  dst X\nLEFT JOIN\n  tmp Y\n    USING(pk1, pk2) -- \u043f\u043e\u043b\u044f \u043f\u0435\u0440\u0432\u0438\u0447\u043d\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0430\nWHERE\n  (D.pk1, D.pk2) = (X.pk1, X.pk2) AND\n  Y IS NOT DISTINCT FROM NULL; -- &quot;\u0430\u043d\u0442\u0438\u0434\u0436\u043e\u0439\u043d&quot;\n\n-- \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u043e\u0441\u0442\u0430\u0432\u0448\u0438\u0435\u0441\u044f\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); -- \u043d\u0435\u0437\u0430\u0447\u0435\u043c \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0449\u0438\u0435\n\n-- \u0432\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435\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. P\u00f3s-processamento da importa\u00e7\u00e3o<\/h3>\n<p>\nNa mesma KLRD, todos os registros alterados precisam ser executados por um p\u00f3s-processamento \u2014 normalizar, destacar palavras-chave, trazer para as estruturas necess\u00e1rias. Mas como saber \u2014 <b>o que exatamente foi alterado<\/b>, sem complicar o c\u00f3digo de sincroniza\u00e7\u00e3o, idealmente, sem at\u00e9 mesmo toc\u00e1-lo?<\/p>\n<p>Se o acesso de grava\u00e7\u00e3o no momento da sincroniza\u00e7\u00e3o \u00e9 apenas para o seu processo, voc\u00ea pode usar um gatilho que coletar\u00e1 todas as altera\u00e7\u00f5es para n\u00f3s:<\/p>\n<pre><code class=\"sql\">-- ciljne tabele\nCREATE TABLE kladr(...);\nCREATE TABLE kladr_house(...);\n\n-- tabele sa istorijom promena\nCREATE TABLE kladr$log(\n  ro kladr, -- ovde se \u010duvaju ceo zapisi starih\/novih\n  rn kladr\n);\n\nCREATE TABLE kladr_house$log(\n  ro kladr_house,\n  rn kladr_house\n);\n\n-- op\u0161ta funkcija logovanja promena\nCREATE OR REPLACE FUNCTION diff$log() RETURNS trigger AS $$\nDECLARE\n  dst varchar = TG_TABLE_NAME || '$log';\n  stmt text = '';\nBEGIN\n  -- proveravamo potrebu za logovanjem prilikom a\u017euriranja zapisa\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  -- kreiramo zapis loga\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>\nSada mo\u017eemo da prije po\u010detka sinhronizacije postavimo (ili uklju\u010dimo preko <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>\nZatim mirno izvla\u010dimo sve potrebne promene iz log-tabela i propu\u0161tamo ih kroz dodatne obradnike.<\/p>\n<h3>3.3. Uvoz povezanih skupa<\/h3>\n<p>\nGore smo razmatrali slu\u010dajeve kada se strukture podataka izvora i odredi\u0161ta poklapaju. Ali \u0161ta raditi ako se izvoz iz spoljnog sistema razlikuje od strukture koju imamo u svojoj bazi?<\/p>\n<p>Uzmimo za primer \u010duvanje klijenata i njihovih ra\u010duna, klasi\u010dan slu\u010daj \"mnogi-na-jedan\":<\/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>\nA izlaz iz spoljnog izvora dolazi nam u formatu \"sve u jednom\":<\/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>\nO\u010digledno je da podaci o klijentima mogu biti duplicirani u ovom obliku, a osnovna zapis je \"ra\u010dun\":<\/p>\n<pre><code class=\"plaintext\">0123456789;Vasa;A-01;2020-03-16;1000.00\n9876543210;Petar;A-02;2020-03-16;666.00\n0123456789;Vasa;B-03;2020-03-16;9999.00\n<\/code><\/pre>\n<p>\nZa model jednostavno ubacimo na\u0161e test podatke, ali pamtimo \u2014 <code>COPY<\/code> efikasnije!<\/p>\n<pre><code class=\"sql\">INSERT INTO invoice_import\nVALUES\n  ('0123456789', 'Vasa', 'A-01', '2020-03-16', 1000.00)\n, ('9876543210', 'Petar', 'A-02', '2020-03-16', 666.00)\n, ('0123456789', 'Vasa', 'B-03', '2020-03-16', 9999.00);<\/code><\/pre>\n<p>\nPrvo \u0107emo izolovati one \"se\u010deve\" na koje se na\u0161i \"fakti\" pozivaju. U na\u0161em slu\u010daju ra\u010duni se pozivaju na klijente:<\/p>\n<pre><code class=\"sql\">CREATE TEMPORARY TABLE client_import AS\nSELECT DISTINCT ON(client_inn)\n-- \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e SELECT DISTINCT, \u0435\u0441\u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u0432\u0435\u0434\u043e\u043c\u043e \u043d\u0435\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0440\u0435\u0447\u0438\u0432\u044b\n  client_inn inn\n, client_name &quot;name&quot;\nFROM\n  invoice_import;<\/code><\/pre>\n<p>\nDa bi pravilno povezali ra\u010dune z ID-ji strank, moramo te identifikatorje najprej poznati ali jih generirati. Dodali bomo polja zanje:<\/p>\n<pre><code class=\"sql\">SPREMENITE TABELO invoice_import DODAJ KOLONO client_id integer;\nSPREMENITE TABELO client_import DODAJ KOLONO client_id integer;<\/code><\/pre>\n<p>\nUporabili bomo zgoraj opisani na\u010din sinhronizacije tabel z majhno prilagoditvijo \u2014 ne bomo niti posodabljali niti brisali v ciljni tabeli, saj imamo uvoz strank \"append-only\":<\/p>\n<pre><code class=\"sql\">-- v tabeli uvoza nastavimo ID \u017ee obstoje\u010dih zapisov\nPOSODABAJANJE\n  client_import T\nNASTAVI\n  client_id = D.client_id\nIZ\n  client D\nKJER\n  T.inn = D.inn; -- edinstven klju\u010d\n\n-- dodamo manjkajo\u010de zapise in nastavimo njihove ID-je\nS WITH ins AS (\n  VSTAVI V client(\n    inn\n  , name\n  )\n  IZBERITE\n    inn\n  , name\n  IZ\n    client_import\n  KJER\n    client_id JE NULL -- \u010de ID ni bil nastavljen\n  VRA\u010cAJU\u010cI *\n)\nPOSODABAJANJE\n  client_import T\nNASTAVI\n  client_id = D.client_id\nIZ\n  ins D\nKJER\n  T.inn = D.inn; -- edinstven klju\u010d\n\n-- nastavimo ID strank pri zapisih ra\u010dunov\nPOSODABAJANJE\n  invoice_import T\nNASTAVI\n  client_id = D.client_id\nIZ\n  client_import D\nKJER\n  T.client_inn = D.inn; -- aplikativni klju\u010d\n<\/code><\/pre>\n<p>\nPravzaprav je to vse \u2014 v <code>invoice_import<\/code> zdaj imamo izpolnjen povezovalni polje <code>client_id<\/code>, s katerim bomo dodali ra\u010dun.<br \/>\n<br \/>Izvor: <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 5.0.4 - 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.\" \/>\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\/sl\/blog\/administrirovanie\/dba-gramotno-organizovyvaem-sinhronizaczii-i-importy\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.4\" \/>\n\t\t<meta property=\"og:locale\" content=\"sl_SI\" \/>\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.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/sl\/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: pametno organiziramo sinhronizacije in uvoze | ProHoster","description":"Pri zapleteni obdelavi velikih naborov podatkov (razni ETL procesi: uvozi, pretvorbe in sinhronizacije z zunanjim virom) pogosto.","canonical_url":"https:\/\/prohoster.info\/sl\/blog\/administrirovanie\/dba-gramotno-organizovyvaem-sinhronizaczii-i-importy","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"sl_SI","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.","og:url":"https:\/\/prohoster.info\/sl\/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","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/posts\/74953","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/comments?post=74953"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/posts\/74953\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/media\/74954"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/media?parent=74953"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/categories?post=74953"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/tags?post=74953"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}