{"id":35259,"date":"2019-10-31T22:03:17","date_gmt":"2019-10-31T19:03:17","guid":{"rendered":"https:\/\/prohoster.info\/blog\/istoriya-odnogo-sql-rassledovaniya\/"},"modified":"2019-10-31T22:03:17","modified_gmt":"2019-10-31T19:03:17","slug":"istoriya-odnogo-sql-rassledovaniya","status":"publish","type":"post","link":"https:\/\/prohoster.info\/sl\/blog\/administrirovanie\/istoriya-odnogo-sql-rassledovaniya","title":{"rendered":"Zgodba enega SQL pregleda","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Decembra lani sem prejel zanimivo poro\u010dilo o napaki od ekipe za podporo VWO. \u010cas nalaganja enega od analiti\u010dnih poro\u010dil za velikega korporativnega klienta se je zdel izjemno dolg. Glede na to, da je to podro\u010dje moje odgovornosti, sem se takoj osredoto\u010dil na re\u0161itev te\u017eave.<\/p>\n<p><\/p>\n<h2>Pozadina<\/h2>\n<p><\/p>\n<p>Da bo jasno, o \u010dem govorim, bom na kratko predstavil VWO. To je platforma, s katero lahko izvajate razli\u010dne ciljne kampanje na svojih spletnih straneh: izvajate A\/B eksperimente, spremljate obiskovalce in konverzije, analizirate prodajne lijake, prikazujete toplotne zemljevide in predvajate posnetke obiskov.<\/p>\n<p><\/p>\n<p>Toda najpomembnej\u0161a funkcija platforme je priprava poro\u010dil. Vse zgoraj omenjene funkcije so med seboj povezane. Za korporativne stranke bi bil velik obseg informacij preprosto brez smisla brez mo\u010dne platforme, ki jih predstavlja v analiti\u010dni obliki.<\/p>\n<p><\/p>\n<p>Z uporabo platforme lahko postavite poljuben zahtevek na velikem naboru podatkov. Tukaj je preprost primer:<\/p>\n<p><\/p>\n<pre>Prika\u017ei vse klike na strani \"abc.com\"\nOD &lt;datuma d1&gt; DO &lt;datuma d2&gt;\nza ljudi, ki\nso uporabili Chrome ALI\n(sobili v Evropi IN uporabljali iPhone)<\/pre>\n<p><\/p>\n<p>Upo\u0161tevajte logi\u010dne operatorje. Ti so na voljo klientom v vmesniku za poizvedbe, da bi omogo\u010dili \u010dim bolj kompleksne poizvedbe za pridobivanje vzorcev.<\/p>\n<p><\/p>\n<h2>Po\u010dasen poizvedba<\/h2>\n<p><\/p>\n<p>Klient, o katerem govorimo, je posku\u0161al narediti nekaj, kar intuitivno deluje hitro:<\/p>\n<p><\/p>\n<pre>Prika\u017ei vse zapise sej\nza uporabnike, ki so obiskali katerokoli stran\ns URL-jem, ki vsebuje \"\\\/jobs\"<\/pre>\n<p><\/p>\n<p>Na tej spletni strani je bilo ogromno prometa, shranili smo ve\u010d kot milijon edinstvenih URL-jev samo za to. In \u017eeleli so najti precej preprost vzorec URL-ja, ki se nana\u0161a na njihov poslovni model.<\/p>\n<p>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Predhodno preiskovanje<\/h2>\n<p><\/p>\n<p>Poglejmo, kaj se dogaja v bazi podatkov. Spodaj je izvirni po\u010dasen SQL poizvedba:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">SELECT \n    count(*) \nFROM \n    acc_{account_id}.urls as recordings_urls, \n    acc_{account_id}.recording_data as recording_data, \n    acc_{account_id}.sessions as sessions \nWHERE \n    recording_data.usp_id = sessions.usp_id \n    AND sessions.referrer_id = recordings_urls.id \n    AND  (  urls &amp;&amp;  array(select id from acc_{account_id}.urls where url  ILIKE  '%enterprise_customer.com\\\/jobs%')::text[]   ) \n    AND r_time &gt; to_timestamp(1542585600) \n    AND r_time &lt; to_timestamp(1545177599) \n    AND recording_data.duration &gt;=5 \n    AND recording_data.num_of_pages &gt; 0 ;<\/code><\/pre>\n<p><\/p>\n<p>Tukaj so \u010dasovne oznake:<\/p>\n<p><\/p>\n<pre>Na\u010drtovani \u010das: 1.480 ms\n\u010cas izvedbe: 1431924.650 ms<\/pre>\n<p><\/p>\n<p>Poizvedba je obdelala 150 tiso\u010d vrstic. Na\u010drtovalec poizvedb je pokazal nekaj zanimivih podrobnosti, a nobenih o\u010ditnih ozkih grl.<\/p>\n<p><\/p>\n<p>Poglejmo \u0161e naprej to poizvedbo. Kot je razvidno, dela <code>JOIN<\/code> treh tabel:<\/p>\n<p><\/p>\n<ol>\n<li><strong>sessions<\/strong>: za prikaz informacij o sejah: brskalnik, uporabni\u0161ka agenta, dr\u017eava itd.<\/li>\n<li><strong>recording_data<\/strong>: zabele\u017eeni URL-ji, strani, trajanje obiskov<\/li>\n<li><strong>urls<\/strong>: da bi se izognili podvajanju izjemno dolgih URL-jev, jih shranjujemo v lo\u010deno tabelo.<\/li>\n<\/ol>\n<p><\/p>\n<p>Prav tako bodite pozorni, da so vse na\u0161e tabele \u017ee razdeljene po <code>account_id<\/code>. S tem je izklju\u010dena situacija, ko zaradi enega posebej velikega ra\u010duna te\u017eave nastanejo pri drugih.<\/p>\n<p><\/p>\n<h2>V iskanju dokazov<\/h2>\n<p><\/p>\n<p>Ob natan\u010dnej\u0161em pregledu vidimo, da nekaj pri tej konkretni poizvedbi ni v redu. Osvetljiti je vredno to vrstico:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">urls &amp;&amp; array(\n\tselect id from acc_{account_id}.urls \n\twhere url ILIKE '%enterprise_customer.com\/jobs%'\n)::text[]<\/code><\/pre>\n<p><\/p>\n<p>Prva misel je bila, da bi morda zaradi <code>ILIKE<\/code> na vseh teh dolgih URL-jih (imamo ve\u010d kot 1,4 milijona <strong>edinstvenih\u00a0<\/strong>URL-jev, zbranih za ta ra\u010dun) lahko pri\u0161lo do zmanj\u0161anja uspe\u0161nosti.<\/p>\n<p><\/p>\n<p>Ampak ne \u2014 to ni bilo to!<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">SELECT id FROM urls WHERE url ILIKE '%enterprise_customer.com\/jobs%';\n  id\n--------\n ...\n(198661 vrstic)\n\n\u010cas: 5231.765 ms<\/code><\/pre>\n<p><\/p>\n<p>Sama poizvedba za iskanje po vzorcu traja le pet sekund. Iskanje po vzorcu pri milijonu unikatnih URL-jev o\u010ditno ni te\u017eava.<\/p>\n<p><\/p>\n<p>Naslednji osumljenec na seznamu \u2014 nekaj <code>JOIN<\/code>. Morda je njihova pretirana uporaba povzro\u010dila upo\u010dasnitev? Obi\u010dajno <code>JOIN<\/code>\u2018y\u2019 so obvious candidates for performance issues, but I didn't believe our case was typical.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">analytics_db=# SELECT\n    count(*)\nFROM\n    acc_{account_id}.urls as recordings_urls,\n    acc_{account_id}.recording_data_0 as recording_data,\n    acc_{account_id}.sessions_0 as sessions\nWHERE\n    recording_data.usp_id = sessions.usp_id\n    AND sessions.referrer_id = recordings_urls.id\n    AND r_time &gt; to_timestamp(1542585600)\n    AND r_time =5\n    AND recording_data.num_of_pages &gt; 0 ;\n count\n-------\n  8086\n(1 vrstica)\n\n\u010cas: 147.851 ms<\/code><\/pre>\n<p><\/p>\n<p>In to prav tako ni bil na\u0161 primer. <code>JOIN<\/code>\u2018y\u2019 turned out to be quite fast.<\/p>\n<p><\/p>\n<h2>Omejitev kroga osumljencev<\/h2>\n<p><\/p>\n<p>Bil sem pripravljen za\u010deti spreminjati poizvedbo, da bi dosegel kakr\u0161ne koli mo\u017ene izbolj\u0161ave uspe\u0161nosti. Skupaj s timom smo razvili 2 glavna na\u010dina:<\/p>\n<p><\/p>\n<ul>\n<li><strong>Uporabite EXISTS za podpoizvedbo URL-jev<\/strong>: \u017deleli smo ponovno preveriti, ali so te\u017eave s podpoizvedbo za URL-je. Eden od na\u010dinov, kako to dose\u010di, je preprosto uporabiti <code>EXISTS<\/code>. <code>EXISTS<\/code> <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/functions-subquery.html#FUNCTIONS-SUBQUERY-EXISTS\">lahko<\/a><\/noindex> znatno pobolj\u0161ati performanse jer zavr\u0161ava odmah nakon pronalaska jedine linije prema uvjetu.<\/li>\n<\/ul>\n<p><\/p>\n<pre><code class=\"plaintext\">SELECT\n\tcount(*) \nFROM \n    acc_{account_id}.urls as recordings_urls,\n    acc_{account_id}.recording_data as recording_data,\n    acc_{account_id}.sessions as sessions\nWHERE\n    recording_data.usp_id = sessions.usp_id\n    AND  (  1 = 1  )\n    AND sessions.referrer_id = recordings_urls.id\n    AND  (exists(select id from acc_{account_id}.urls where url  ILIKE '%enterprise_customer.com\/jobs%'))\n    AND r_time &gt; to_timestamp(1547585600)\n    AND r_time =5\n    AND recording_data.num_of_pages &gt; 0 ;\n count\n 32519\n(1 row)\nTime: 1636.637 ms<\/code><\/pre>\n<p><\/p>\n<p>Da, podupit, kada je omotan u\u00a0<code>EXISTS<\/code>, \u010dini sve super brzim. Sljede\u0107e logi\u010dno pitanje je za\u0161to je upit s <code>JOIN<\/code>-ima i sam podupit brzi pojedina\u010dno, ali stra\u0161no usporavaju zajedno?<\/p>\n<p><\/p>\n<ul>\n<li><strong>Premje\u0161tamo podupit u CTE <\/strong>: ako je upit brz sam po sebi, mo\u017eemo prvo izra\u010dunati brzi rezultat, a zatim ga osigurati glavnom upitu<\/li>\n<\/ul>\n<p><\/p>\n<pre><code class=\"plaintext\">WITH matching_urls AS (\n    select id::text from acc_{account_id}.urls where url  ILIKE  '%enterprise_customer.com\/jobs%'\n)\n\nSELECT \n    count(*) FROM acc_{account_id}.urls as recordings_urls, \n    acc_{account_id}.recording_data as recording_data, \n    acc_{account_id}.sessions as sessions,\n    matching_urls\nWHERE \n    recording_data.usp_id = sessions.usp_id \n    AND  (  1 = 1  )  \n    AND sessions.referrer_id = recordings_urls.id\n    AND (urls &amp;&amp; array(SELECT id from matching_urls)::text[])\n    AND r_time &gt; to_timestamp(1542585600) \n    AND r_time =5 \n    AND recording_data.num_of_pages &gt; 0;<\/code><\/pre>\n<p><\/p>\n<p>Ali je sve to jo\u0161 uvijek bilo vrlo sporo.<\/p>\n<p><\/p>\n<h2>Pronalazimo krivca<\/h2>\n<p><\/p>\n<p>Tijekom cijelog ovog vremena pred o\u010dima mi se pojavila mala sitnica koju sam stalno odbacivao. No, budu\u0107i da vi\u0161e ni\u0161ta drugo nije ostalo, odlu\u010dio sam malo pogledati i nju. Govorim o <code>&amp;&amp;<\/code> operatoru. Dok <code>EXISTS<\/code> samo pobolj\u0161ao performanse, <code>&amp;&amp;<\/code> bila je jedini preostali zajedni\u010dki faktor u svim verzijama sporog upita.<\/p>\n<p><\/p>\n<p>Gledaju\u0107i <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/9.1\/functions-array.html\">dokumentacijo<\/a><\/noindex>, vidimo da <code>&amp;&amp;<\/code> se koristi kada je potrebno prona\u0107i zajedni\u010dke elemente izme\u0111u dva niza.<\/p>\n<p><\/p>\n<p>U originalnom upitu to je:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">AND  (  urls &amp;&amp;  array(select id from acc_{account_id}.urls where url  ILIKE  '%enterprise_customer.com\/jobs%')::text[]   )<\/code><\/pre>\n<p><\/p>\n<p>\u0160to zna\u010di da tra\u017eimo po obrascu po na\u0161im URL-ovima, zatim pronalazimo presjek sa svim URL-ovima s zajedni\u010dkim zapisima. Ovo je pomalo zbunjuju\u0107e, jer \"urls\" ovdje ne upu\u0107uje na tablicu koja sadr\u017ei sve URL-ove, ve\u0107 na stupac \"urls\" u tablici <code>recording_data<\/code>.<\/p>\n<p><\/p>\n<p>S rastu\u0107im sumnjama u vezi sa <code>&amp;&amp;<\/code>, poku\u0161ao sam prona\u0107i njihovo potvr\u0111enje u planu upita, generiranom <code>EXPLAIN ANALYZE<\/code> (imela sem shranjen na\u010drt, vendar mi je obi\u010dajno bolj priro\u010dno eksperimentirati v SQL kot posku\u0161ati razumeti nejasnosti na\u010drtovalnikov poizvedb).<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">Filter: ((urls &amp;&amp; ($0)::text[]) IN (r_time &gt; '2018-12-17 12:17:23+00'::timestamp with time zone) IN (r_time = '5'::double precision) IN (num_of_pages &gt; 0))\n                           Razi\u0161\u010dene vrstice: 52710<\/code><\/pre>\n<p><\/p>\n<p>Tam je bilo nekaj vrstic filtrov le iz <code>&amp;&amp;<\/code>. Kar je pomenilo, da ta operacija ni bila le draga, ampak je bila izvedena ve\u010dkrat.<\/p>\n<p><\/p>\n<p>To sem preveril, tako da sem izoliral pogoje<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">SELECT 1\nFROM \n    acc_{account_id}.urls kot recordings_urls, \n    acc_{account_id}.recording_data_30 kot recording_data_30, \n    acc_{account_id}.sessions_30 kot sessions_30 \nWHERE \n\turls &amp;&amp; array(select id from acc_{account_id}.urls where url ILIKE '%enterprise_customer.com\/jobs%')::text[]<\/code><\/pre>\n<p><\/p>\n<p>Ta poizvedba se je izvajala po\u010dasi. Ker <code>JOIN<\/code>-i so hitri in podpoizvedbe so hitre, je ostal le <code>&amp;&amp;<\/code> operator.<\/p>\n<p><\/p>\n<p>Samo to je klju\u010dna operacija. Vedno moramo iskati po glavni tabeli URL-jev, da bi iskali po vzorcu, in vedno moramo najti preseke. Ne moremo iskati neposredno po zapisih URL-jev, ker so to le ID-ji, ki se navezujejo na <code>urls<\/code>.<\/p>\n<p><\/p>\n<h2>Na poti do re\u0161itve<\/h2>\n<p><\/p>\n<p><code>&amp;&amp;<\/code> po\u010dasni, ker sta oba niza ogromna. Operacija bo relativno hitra, \u010de zamenjam <code>urls<\/code> na <code>{ \"http:\/\/google.com\/\", \"http:\/\/wingify.com\/\" }<\/code>.<\/p>\n<p><\/p>\n<p>Za\u010del sem iskati na\u010din, kako v Postgresu uporabiti presek mno\u017eic brez <code>&amp;&amp;<\/code>, vendar brez ve\u010djega uspeha.<\/p>\n<p><\/p>\n<p>Na koncu smo se odlo\u010dili, da preprosto re\u0161imo problem izolirano: daj mi vse <code>urls<\/code> lines for which the URL matches the pattern. Without additional conditions, this will be \u2014\u00a0<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">SELECT urls.url\nFROM \n\tacc_{account_id}.urls kot urls,\n\t(SELECT unnest(recording_data.urls) AS id) AS unrolled_urls\nWHERE\n\turls.id = unrolled_urls.id IN\n\turls.url ILIKE '%jobs%'<\/code><\/pre>\n<p><\/p>\n<p>Namesto\u00a0<code>JOIN<\/code> sintaksa sem preprosto uporabil podpoizvedbo in razvil <code>recording_data.urls<\/code> niz, da bi lahko neposredno uporabili pogoj v <code>WHERE<\/code>.<\/p>\n<p><\/p>\n<p>Najpomembnej\u0161e je, <code>&amp;&amp;<\/code> da se uporablja za preverjanje, ali ta zapis vsebuje ustrezen URL. \u010ce se malo skoncentriramo, lahko opazimo, da pri tej operaciji potujemo po elementih niza (ali vrsticah tabele) in se ustavimo, ko se izpolni pogoj (ustreznost). Ni\u010d ne spominja? Aha, <code>EXISTS<\/code>.<\/p>\n<p><\/p>\n<p>Ker <code>recording_data.urls<\/code> lahko sklicujemo izven konteksta podpoizvedbe, ko se to zgodi, se lahko vrnemo k na\u0161emu staremu prijatelju <code>EXISTS<\/code> in ga ovijemo s podpoizvedbo.<\/p>\n<p><\/p>\n<p>Kdaj vse skupaj zdru\u017eimo, dobimo kon\u010dno optimizirano poizvedbo:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">IZBERI \n    \u0161t. \nIZ \n    acc_{account_id}.urls kot recordings_urls, \n    acc_{account_id}.recording_data kot recording_data, \n    acc_{account_id}.sessions kot sessions \nKJER \n    recording_data.usp_id = sessions.usp_id \n    IN  (  1 = 1  )  \n    IN sessions.referrer_id = recordings_urls.id \n    IN r_time &gt; to_timestamp(1542585600) \n    IN r_time =5 \n    IN recording_data.num_of_pages &gt; 0\n    IN OBSTOJI(\n        IZBERI urls.url\n        IZ \n            acc_{account_id}.urls kot urls,\n            (IZBERI unnest(urls) AS rec_url_id IZ acc_{account_id}.recording_data) \n            AS unrolled_urls\n        KJER\n            urls.id = unrolled_urls.rec_url_id IN\n            urls.url ILIKE '%enterprise_customer.com\/jobs%'\n    );\n<\/code><\/pre>\n<p><\/p>\n<p>In kon\u010dni \u010das izvajanja <code>\u010cas: 1898.717 ms<\/code> \u010cas za praznovanje?!?<\/p>\n<p><\/p>\n<p>Ne tako hitro! Najprej moramo preveriti pravilnost. Bil sem izjemno sumljiv glede <code>EXISTS<\/code> optimizacije, ker spreminja logiko na hitrej\u0161e dokon\u010danje. Prepri\u010dati se moramo, da nismo dodali skrite napake v poizvedbo.<\/p>\n<p><\/p>\n<p>Preprost pregled je bil izvajanje <code>count(*)<\/code> in pri po\u010dasnih in hitrih poizvedbah za veliko razli\u010dnih sklopov podatkov. Nato sem za manj\u0161i podsklop podatkov ro\u010dno preveril pravilnost vseh rezultatov.<\/p>\n<p><\/p>\n<p>Vse preglede so dale dosledno pozitivne rezultate. Vse smo popravili!<\/p>\n<p><\/p>\n<h2>Izku\u0161ene Lekcije<\/h2>\n<p><\/p>\n<p>Iz te zgodbe lahko pridobimo veliko lekcij:<\/p>\n<p><\/p>\n<ol>\n<li>Na\u010drti poizvedb ne povedo vse zgodbe, lahko pa dajo namige<\/li>\n<li>Glavni osumljenci niso vedno pravi storilci<\/li>\n<li>Po\u010dasne poizvedbe je mogo\u010de razdeliti, da izoliramo ozka grla<\/li>\n<li>Ne vse optimizacije so po naravi reduktivne<\/li>\n<li>Uporaba <code>EXIST<\/code>, kjer je to mogo\u010de, lahko privede do drasti\u010dnega pove\u010danja zmogljivosti<\/li>\n<\/ol>\n<p><\/p>\n<h2>Izlaz<\/h2>\n<p><\/p>\n<p>Pre\u0161li smo od \u010dasa poizvedbe pribli\u017eno 24 minut do 2 sekund \u2014 precej resno pove\u010danje zmogljivosti! \u010ceprav je ta \u010dlanek dolg, so se vsi eksperimenti, ki smo jih izvedli, zgodili v enem dnevu in po ocenah trajali med 1,5 in 2 uri za optimizacijo in testiranje.<\/p>\n<p><\/p>\n<p>SQL je \u010dudovit jezik, \u010de se ga ne bojite, temve\u010d posku\u0161ate razumeti in uporabljati. Z dobrim razumevanjem, kako se izvajajo SQL poizvedbe, kako DB generira na\u010drte poizvedb, kako delujejo indeksi in preprosto velikost podatkov, ki jih imate, lahko zelo napredujete pri optimizaciji poizvedb. Enako pomembno pa je, da \u0161e naprej preizku\u0161ate razli\u010dne pristope in po\u010dasi razdelite te\u017eave, pri tem pa raziskujete ozka grla.<\/p>\n<p><\/p>\n<p>Najbolj\u0161a stvar pri doseganju takih rezultatov je opazno izbolj\u0161anje hitrosti delovanja \u2014 poro\u010dilo, ki se prej sploh ni nalo\u017eilo, se zdaj nalo\u017ei skoraj takoj.<\/p>\n<p><\/p>\n<p><strong>Posebna zahvala\u00a0<\/strong>mojim kolegom\u00a0<em>v ekipi Aditya Mishra<\/em>,\u00a0<em>Aditya Gaur\u00a0<\/em>in\u00a0<em><noindex><a rel=\"nofollow\" href=\"https:\/\/twitter.com\/s0ftvar\">Varun Malhotra\u00a0<\/a><\/noindex><\/em>za brainstorm in\u00a0<em>Dinkar Pandir\u00a0<\/em>za to, da je na\u0161el pomembno napako v na\u0161i kon\u010dni zahtevi, preden smo se dokon\u010dno poslovili!<\/p>\n<p>Izvor: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/455832\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0412 \u0434\u0435\u043a\u0430\u0431\u0440\u0435 \u043f\u0440\u043e\u0448\u043b\u043e\u0433\u043e \u0433\u043e\u0434\u0430 \u044f \u043f\u043e\u043b\u0443\u0447\u0438\u043b \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u043e\u0442\u0447\u0435\u0442 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435 \u043e\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u044b\u00a0\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 VWO. \u0412\u0440\u0435\u043c\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u043e\u0442\u0447\u0435\u0442\u043e\u0432 \u0434\u043b\u044f \u043a\u0440\u0443\u043f\u043d\u043e\u0433\u043e \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u043d\u0435\u043f\u043e\u043c\u0435\u0440\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0438\u043c. \u0410 \u0442\u0430\u043a \u043a\u0430\u043a \u044d\u0442\u043e \u0441\u0444\u0435\u0440\u0430 \u043c\u043e\u0435\u0439 \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u0438, \u044f \u0442\u0443\u0442 \u0436\u0435 \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0438\u043b\u0441\u044f \u043d\u0430 \u0440\u0435\u0448\u0435\u043d\u0438\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b. \u041f\u0440\u0435\u0434\u044b\u0441\u0442\u043e\u0440\u0438\u044f \u0427\u0442\u043e\u0431\u044b \u0431\u044b\u043b\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u043e \u043e \u0447\u0451\u043c \u0440\u0435\u0447\u044c, \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u0441\u043e\u0432\u0441\u0435\u043c \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043e VWO. \u042d\u0442\u043e \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430, [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-35259","post","type-post","status-publish","format-standard","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=\"\u0412 \u0434\u0435\u043a\u0430\u0431\u0440\u0435 \u043f\u0440\u043e\u0448\u043b\u043e\u0433\u043e \u0433\u043e\u0434\u0430 \u044f \u043f\u043e\u043b\u0443\u0447\u0438\u043b \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u043e\u0442\u0447\u0435\u0442 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435 \u043e\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 VWO. \u0412\u0440\u0435\u043c\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u043e\u0442\u0447\u0435\u0442\u043e\u0432 \u0434\u043b\u044f \u043a\u0440\u0443\u043f\u043d\u043e\u0433\u043e \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u043d\u0435\u043f\u043e\u043c\u0435\u0440\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0438\u043c.\" \/>\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\/istoriya-odnogo-sql-rassledovaniya\" \/>\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\udd47\u0418\u0441\u0442\u043e\u0440\u0438\u044f \u043e\u0434\u043d\u043e\u0433\u043e SQL \u0440\u0430\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0412 \u0434\u0435\u043a\u0430\u0431\u0440\u0435 \u043f\u0440\u043e\u0448\u043b\u043e\u0433\u043e \u0433\u043e\u0434\u0430 \u044f \u043f\u043e\u043b\u0443\u0447\u0438\u043b \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u043e\u0442\u0447\u0435\u0442 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435 \u043e\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 VWO. \u0412\u0440\u0435\u043c\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u043e\u0442\u0447\u0435\u0442\u043e\u0432 \u0434\u043b\u044f \u043a\u0440\u0443\u043f\u043d\u043e\u0433\u043e \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u043d\u0435\u043f\u043e\u043c\u0435\u0440\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0438\u043c.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/sl\/blog\/administrirovanie\/istoriya-odnogo-sql-rassledovaniya\" \/>\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=\"2019-10-31T19:03:17+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T19:03:17+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\udd47Zgodba o enem SQL preiskovanju | ProHoster","description":"Decembra lani sem prejel zanimivo poro\u010dilo o napaki od podporne ekipe VWO. \u010cas nalaganja enega od analiti\u010dnih poro\u010dil za velikega poslovnega naro\u010dnika se je zdela pretirano dolg.","canonical_url":"https:\/\/prohoster.info\/sl\/blog\/administrirovanie\/istoriya-odnogo-sql-rassledovaniya","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\udd47\u0418\u0441\u0442\u043e\u0440\u0438\u044f \u043e\u0434\u043d\u043e\u0433\u043e SQL \u0440\u0430\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f | ProHoster","og:description":"\u0412 \u0434\u0435\u043a\u0430\u0431\u0440\u0435 \u043f\u0440\u043e\u0448\u043b\u043e\u0433\u043e \u0433\u043e\u0434\u0430 \u044f \u043f\u043e\u043b\u0443\u0447\u0438\u043b \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u043e\u0442\u0447\u0435\u0442 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435 \u043e\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 VWO. \u0412\u0440\u0435\u043c\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u043e\u0442\u0447\u0435\u0442\u043e\u0432 \u0434\u043b\u044f \u043a\u0440\u0443\u043f\u043d\u043e\u0433\u043e \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u043d\u0435\u043f\u043e\u043c\u0435\u0440\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0438\u043c.","og:url":"https:\/\/prohoster.info\/sl\/blog\/administrirovanie\/istoriya-odnogo-sql-rassledovaniya","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":"2019-10-31T19:03:17+00:00","article:modified_time":"2019-10-31T19:03:17+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"35259","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":"2026-01-21 22:33:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 02:07:28","updated":"2026-01-21 22:33:19","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\/35259","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=35259"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/posts\/35259\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/media?parent=35259"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/categories?post=35259"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/tags?post=35259"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}