{"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\/et\/blog\/administrirovanie\/istoriya-odnogo-sql-rassledovaniya","title":{"rendered":"\u00dche SQL-uuringu lugu","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Eelmise aasta detsembris sain VWO tugimeeskonnalt huvitava veateate. \u00dche anal\u00fc\u00fcsiaruande laadimisaeg suure ettev\u00f5tte kliendi jaoks n\u00e4is olevat \u00fclem\u00e4\u00e4ra pikk. Kuna see kuulub minu vastutusalasse, keskendusin viivitamatult probleemi lahendamisele.<\/p>\n<p><\/p>\n<h2>Eelalugu<\/h2>\n<p><\/p>\n<p>Et oleks selge, millest jutt, r\u00e4\u00e4gin pisut VWO-st. See on platvorm, millega saab oma saitidel k\u00e4ivitada erinevaid sihitud kampaaniaid: teostada A\/B katseid, j\u00e4lgida k\u00fclastajaid ja konversioone, teha m\u00fc\u00fcgivihje anal\u00fc\u00fcse, kuvada soojuskaarte ja esitada k\u00fclastuse salvestusi.<\/p>\n<p><\/p>\n<p>Kuid k\u00f5ige olulisem platvormi aspekt on aruannete koostamine. K\u00f5ik eelnevalt mainitud funktsioonid on omavahel seotud. Suur hulk teavet oleks ettev\u00f5tte klientidele lihtsalt kasutuks, kui see ei oleks esitatud anal\u00fc\u00fcsimiseks m\u00f5eldud platvormi kaudu.<\/p>\n<p><\/p>\n<p>Platvormi abil saab teha vabalt valitud p\u00e4ringu suure hulga andmete pealt. Siin on lihtne n\u00e4ide:<\/p>\n<p><\/p>\n<pre>Kuva k\u00f5ik kl\u00f5psud lehel \"abc.com\" \nPERIOODILT &lt;kuup\u00e4ev d1&gt; KUNI &lt;kuup\u00e4ev d2&gt; \ninimeste jaoks, kes \nkasutasid Chrome'i V\u00d5I \n(olid Euroopas JA kasutasid iPhone'i)<\/pre>\n<p><\/p>\n<p>Pange t\u00e4hele loogika operaatorite olemust. Need on saadaval klientide p\u00e4ringu liideses, et luua piisavalt keerulisi p\u00e4ringuid andmestike saamiseks.<\/p>\n<p><\/p>\n<h2>Aeglane p\u00e4ring<\/h2>\n<p><\/p>\n<p>Kliendil, millest me r\u00e4\u00e4gime, oli soov teha midagi, mis intuitiivselt peaks t\u00f6\u00f6tama kiiresti:<\/p>\n<p><\/p>\n<pre>Kuva k\u00f5ik seansi salvestused \nk\u00fclastajate jaoks, kes on k\u00e4inud mis tahes lehel \nURL-iga, mis sisaldab \"\/jobs\".<\/pre>\n<p><\/p>\n<p>Saidil oli tohutult liiklust, ja me s\u00e4ilitasime \u00fcle miljoni unikaalse URL-aadressi vaid selle jaoks. Nad soovisid leida \u00fcsnagi lihtsa URL-malli, mis seondub nende \u00e4rimudeliga.<\/p>\n<p>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Eeluurimine<\/h2>\n<p><\/p>\n<p>Vaatame, mis toimub andmebaasis. Allpool on algne aeglane SQL-p\u00e4ring:<\/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>Siin on ajad:<\/p>\n<p><\/p>\n<pre>Eeldatav aeg: 1.480 ms\nT\u00e4itmise aeg: 1431924.650 ms<\/pre>\n<p><\/p>\n<p>P\u00e4ring l\u00e4bis 150 tuhat rida. P\u00e4ringu planeerija n\u00e4itas m\u00f5ningaid huvitavaid detaile, kuid mingeid ilmseid kitsaskohti ei olnud.<\/p>\n<p><\/p>\n<p>Vaatame p\u00e4ringut p\u00f5hjalikumalt. Nagu n\u00e4ha, tegeleb see <code>JOIN<\/code> kolme tabeliga:<\/p>\n<p><\/p>\n<ol>\n<li><strong>sessions<\/strong>: seansi teabe kuvamiseks: brauser, kasutajaagent, riik jne.<\/li>\n<li><strong>recording_data<\/strong>: salvestatud URL-id, lehek\u00fcljed, visiitide kestus.<\/li>\n<li><strong>urls<\/strong>: et v\u00e4ltida \u00e4\u00e4rmiselt suurte URL-ide dubleerimist, s\u00e4ilitame need eraldi tabelis.<\/li>\n<\/ol>\n<p><\/p>\n<p>Pange t\u00e4hele, et k\u00f5ik meie tabelid on juba jagatud <code>account_id<\/code>. Seega elimineeritakse olukord, kus \u00fche \u00fclem\u00e4\u00e4ra suure konto t\u00f5ttu tekivad probleemid \u00fclej\u00e4\u00e4nutele.<\/p>\n<p><\/p>\n<h2>T\u00f5endite otsing<\/h2>\n<p><\/p>\n<p>S\u00fcvenedes, m\u00e4rkame, et konkreetse p\u00e4ringu korral on midagi valesti. Tasub t\u00e4helepanu p\u00f6\u00f6rata sellele reale:<\/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>Esimene m\u00f5te oli, et \u00e4kki, kuna <code>ILIKE<\/code> k\u00f5ikide nende pikkade URL-ide korral (meil on \u00fcle 1,4 miljoni <strong>unikaalse\u00a0<\/strong>URL-aadressi, mis on selle konto jaoks kogutud) v\u00f5ib j\u00f5udlus langetada.<\/p>\n<p><\/p>\n<p>Aga ei \u2014 asi pole selles!<\/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 real)\n\nAeg: 5231.765 ms<\/code><\/pre>\n<p><\/p>\n<p>Otsingup\u00e4ring mallide j\u00e4rgi v\u00f5tab ainult 5 sekundit. Mallide p\u00f5hjal otsimine \u00fcle miljoni unikaalse URL-i osas pole kindlasti probleem.<\/p>\n<p><\/p>\n<p>J\u00e4rgmine kahtlane kahtlane \u2014 mitu <code>JOIN<\/code>. V\u00f5ib-olla nende \u00fclem\u00e4\u00e4rane kasutamine viis aeglustumise juurde? Tavaliselt <code>JOIN<\/code>Need on k\u00f5ige ilmsemad kandidaadid j\u00f5udlusprobleemideks, kuid ma ei usu, et meie juhtum on t\u00fc\u00fcpiline.<\/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 &lt; to_timestamp(1545177599)\n    AND recording_data.duration &gt;=5\n    AND recording_data.num_of_pages &gt; 0 ;\n count\n-------\n  8086\n(1 rida)\n\nAeg: 147.851 ms<\/code><\/pre>\n<p><\/p>\n<p>Ja see ei olnud ka meie juhtum. <code>JOIN<\/code>Need osutusid \u00fcllatavalt kiireteks.<\/p>\n<p><\/p>\n<h2>Kitsendame kahtlusi<\/h2>\n<p><\/p>\n<p>Olin valmis hakkama p\u00e4ringut muutma, et saavutada v\u00f5imalikult suur j\u00f5udluse paranemine. Meie meeskond v\u00e4lja t\u00f6\u00f6tas kaks peamist ideed:<\/p>\n<p><\/p>\n<ul>\n<li><strong>Kasuta EXISTS-i URLi alamp\u00e4ringu suhtes<\/strong>: Soovisime veel kord kontrollida, kas URL-i alamp\u00e4ringuga on probleeme. \u00dcks v\u00f5imalus selleks on lihtsalt kasutada <code>EXISTS<\/code>. <code>EXISTS<\/code> <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/functions-subquery.html#FUNCTIONS-SUBQUERY-EXISTS\">suuteline<\/a><\/noindex> t\u00f5hususe suurendamiseks, kuna see l\u00f5ppeb kohe, kui leiab \u00fcksiku rea vastavalt tingimusele.<\/li>\n<\/ul>\n<p><\/p>\n<pre><code class=\"plaintext\">VALI\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>Jah, alamp\u00e4ring, kui see on \u00fcmber.\u00a0<code>EXISTS<\/code>, muudab k\u00f5ik \u00fclikiireks. J\u00e4rgmine loogiline k\u00fcsimus on, miks p\u00e4ringud koos <code>JOIN<\/code>-dega ja alamp\u00e4ringud t\u00f6\u00f6tavad eraldi kiiresti, aga koos on nad hirmsasti aeglased?<\/p>\n<p><\/p>\n<ul>\n<li><strong>Viime alamp\u00e4ringu CTE-sse <\/strong>: kui p\u00e4ring t\u00f6\u00f6tab kiiresti iseenesest, saame k\u00f5igepealt kiire tulemuse arvutada ja seej\u00e4rel esitada selle p\u00f5hik\u00fcsimusele.<\/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>Aga isegi see oli endiselt v\u00e4ga aeglane.<\/p>\n<p><\/p>\n<h2>Leidke s\u00fc\u00fcdlane<\/h2>\n<p><\/p>\n<p>Kogu selle aja silme ees oli \u00fcks detail, millest ma pidevalt eemale t\u00f5ukasin. Aga kuna rohkem ei olnud j\u00e4\u00e4nud, otsustasin sellele siiski pilgu heita. Ma r\u00e4\u00e4gin <code>&amp;&amp;<\/code> operaator. Seni <code>EXISTS<\/code> lihtsalt parandas j\u00f5udlust, <code>&amp;&amp;<\/code> oli ainus veel alles j\u00e4\u00e4nud \u00fchine tegur k\u00f5igis aeglaste p\u00e4ringute versioonides.<\/p>\n<p><\/p>\n<p>Vaadates <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/9.1\/functions-array.html\">dokumentatsiooni<\/a><\/noindex>, n\u00e4eme, et <code>&amp;&amp;<\/code> kasutatakse, kui on vaja leida \u00fchiseid elemente kahe massiivi vahel.<\/p>\n<p><\/p>\n<p>Originaalses p\u00e4ringus on see:<\/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>See t\u00e4hendab, et me teeme mustriotsingut meie URL-ide \u00fcle ja seej\u00e4rel leiame l\u00f5ike k\u00f5igist URL-idest, millel on \u00fchised salvestused. See on veidi segane, kuna 'urls' ei viita tabelile, mis sisaldab k\u00f5iki URL-e, vaid veerule 'urls' tabelis <code>recording_data<\/code>.<\/p>\n<p><\/p>\n<p>Kasvatades kahtlusi <code>&amp;&amp;<\/code>, \u00fcritasin leida neile t\u00f5estust p\u00e4ringu plaani kaudu, mille genereeris <code>EXPLAIN ANALYZE<\/code> (mul oli juba salvestatud plaan, kuid mulle meeldib tavaliselt SQL-is eksperimenteerida pigem, kui p\u00fc\u00fcda m\u00f5ista p\u00e4ringute planeerijate l\u00e4bipaistmatust).<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">Filter: ((urls &amp;&amp; ($0)::text[]) AND (r_time &gt; '2018-12-17 12:17:23+00'::timestamp with time zone) AND (r_time = '5'::double precision) AND (num_of_pages &gt; 0))\n                           Rows Removed by Filter: 52710<\/code><\/pre>\n<p><\/p>\n<p>Seal oli mitmeid filtreerimisridasid ainult <code>&amp;&amp;<\/code>. Mis t\u00e4hendas, et see operatsioon polnud mitte ainult kulukas, vaid toimus mitu korda.<\/p>\n<p><\/p>\n<p>Kontrollisin seda, isoleerides tingimuse<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">SELECT 1\nFROM \n    acc_{account_id}.urls as recordings_urls, \n    acc_{account_id}.recording_data_30 as recording_data_30, \n    acc_{account_id}.sessions_30 as 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>See p\u00e4ring t\u00f6\u00f6tas aeglaselt. Kuna <code>JOIN<\/code>-d on kiire ja alamp\u00e4ringud kiired, j\u00e4i alles ainult <code>&amp;&amp;<\/code> operaator.<\/p>\n<p><\/p>\n<p>Kuid see on v\u00f5tmeoperatsioon. Me peame alati otsima pealt suures URL-de tabelis, et mustri p\u00f5hjal otsida, ja me peame alati leidma l\u00f5ike. Me ei saa otsida URL-i salvestusi otse, kuna need on lihtsalt ID-d, mis viitavad <code>urls<\/code>.<\/p>\n<p><\/p>\n<h2>Lahenduse poole liikudes<\/h2>\n<p><\/p>\n<p><code>&amp;&amp;<\/code> aeglaseks, kuna m\u00f5lemad komplektid on tohutud. Operatsioon on suhteliselt kiire, kui asendan <code>urls<\/code> j\u00e4rgnevaga <code>{ \"http:\/\/google.com\/\", \"http:\/\/wingify.com\/\" }<\/code>.<\/p>\n<p><\/p>\n<p>Alustasin viisi otsimist, kuidas teha Postgresis kogumite l\u00f5ikeid ilma <code>&amp;&amp;<\/code>, kuid ei olnud erilisi edusamme.<\/p>\n<p><\/p>\n<p>L\u00f5puks otsustasime lihtsalt probleemi isoleeritult lahendada: andke mulle k\u00f5ik <code>urls<\/code> read, mille URL vastab mustrile. Ilma t\u00e4iendavate tingimusteta on see \u2014\u00a0<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">SELECT urls.url\nFROM \n\tacc_{account_id}.urls as urls,\n\t(SELECT unnest(recording_data.urls) AS id) AS unrolled_urls\nWHERE\n\turls.id = unrolled_urls.id AND\n\turls.url  ILIKE  '%jobs%'<\/code><\/pre>\n<p><\/p>\n<p>Asetame\u00a0<code>JOIN<\/code> S\u00fcntaksit kasutasin lihtsalt alamp\u00e4ringut ja lahti keritud <code>recording_data.urls<\/code> massiiv, et saaksime otse rakendada tingimust <code>WHERE<\/code>.<\/p>\n<p><\/p>\n<p>K\u00f5ige olulisem on see, et <code>&amp;&amp;<\/code> kasutatakse selle kontrollimiseks, kas antud salvestusel on vastav URL-aadress. Veidi pilku keerates v\u00f5ib n\u00e4ha, et see operatsioon liigub massiivi (v\u00f5i tabeli ridade) elementide kaudu ja peatub, kui tingimust (vastavust) t\u00e4idetakse. Kas see ei tuleta meelde midagi? Ah, <code>EXISTS<\/code>.<\/p>\n<p><\/p>\n<p>Kuna <code>recording_data.urls<\/code> v\u00f5ib viidata konteksti v\u00e4ljastpoolt alamp\u00e4ringut, kui see juhtub, saame naasta tagasi meie vanale s\u00f5brale <code>EXISTS<\/code> ja \u00fcmbritseda selle alamp\u00e4ringuga.<\/p>\n<p><\/p>\n<p>Kokkuv\u00f5ttes saame l\u00f5pliku optimeeritud p\u00e4ringu:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">VALI \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  (  1 = 1  )  \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    AND EXIST(\n        SELECT urls.url\n        FROM \n            acc_{account_id}.urls as urls,\n            (SELECT unnest(urls) AS rec_url_id FROM acc_{account_id}.recording_data) \n            AS unrolled_urls\n        WHERE\n            urls.id = unrolled_urls.rec_url_id AND\n            urls.url  ILIKE  '%enterprise_customer.com\/jobs%'\n    );\n<\/code><\/pre>\n<p><\/p>\n<p>Ja l\u00f5plik t\u00e4itmise aeg <code>Aeg: 1898.717 ms<\/code> Kas on pidu pidada?!?<\/p>\n<p><\/p>\n<p>Aga mitte nii kiiresti! Esiteks peame kontrollima korrektsust. Olin v\u00e4ga ettevaatlik <code>EXISTS<\/code> optimeerimise suhtes, kuna see muudab loogikat varasemaks l\u00f5petamiseks. Me peame olema kindlad, et me ei ole lisanud pettumust valmistavat viga p\u00e4ringusse.<\/p>\n<p><\/p>\n<p>Lihtne kontroll seisnes selles, et tegin <code>count(*)<\/code> ja aeglaste ja kiirete p\u00e4ringute kohta suure hulga erinevate andme komplektide jaoks. Seej\u00e4rel, v\u00e4ikese andmekogumi jaoks kontrollisin k\u00f5igi tulemuste \u00f5igsust k\u00e4sitsi.<\/p>\n<p><\/p>\n<p>K\u00f5ik kontrollid andsid pidevalt positiivseid tulemusi. Me oleme k\u00f5ik korda teinud!<\/p>\n<p><\/p>\n<h2>T\u00f5ukude \u00d5ppetunnid<\/h2>\n<p><\/p>\n<p>Selle looga saab v\u00f5tta palju \u00f5ppetunde:<\/p>\n<p><\/p>\n<ol>\n<li>P\u00e4ringu plaanid ei r\u00e4\u00e4gi kogu lugu, kuid v\u00f5ivad anda vihjeid<\/li>\n<li>Peamised kahtlusalused ei ole alati tegelikud s\u00fc\u00fcdlased<\/li>\n<li>Aeglaseid p\u00e4ringuid saab jagada, et kitsaskohti isoleerida<\/li>\n<li>Kaugel ei ole k\u00f5ik optimeerimised oma olemuselt reduktiivsed<\/li>\n<li>Kasutamine <code>EXIST<\/code>, kus see on v\u00f5imalik, v\u00f5ib viia oluliseks j\u00f5udluse kasvuks<\/li>\n<\/ol>\n<p><\/p>\n<h2>Kokkuv\u00f5te<\/h2>\n<p><\/p>\n<p>Oleme liikunud p\u00e4ringu ajast ~24 minutist 2 sekundini \u2014 v\u00e4ga t\u00f5sine j\u00f5udluse kasv! Kuigi see artikkel on suur, toimusid k\u00f5ik meie eksperimendid \u00fche p\u00e4eva jooksul ja nende teostamiseks ja testimiseks kulus umbes 1,5 kuni 2 tundi.<\/p>\n<p><\/p>\n<p>SQL on imeline keel, kui mitte karta seda, vaid proovida m\u00f5ista ja kasutada. H\u00e4id teadmisi, kuidas SQL p\u00e4ringud toimuvad, kuidas andmebaasid genereerivad p\u00e4ringuplaanid, kuidas indeksid t\u00f6\u00f6tavad ja lihtsalt andmekoguse kohta, millega tegelete, saate p\u00e4ringute optimeerimises v\u00e4ga h\u00e4sti hakkama. Samuti on oluline j\u00e4tkata erinevate l\u00e4henemiste testimist ja aeglaselt probleeme lahendada, leides kitsaskohad.<\/p>\n<p><\/p>\n<p>Parim osa selliste tulemuste saavutamisel on m\u00e4rgatav kiiruset\u00f5us \u2014 kui raport, mis varem ei launud, launeb n\u00fc\u00fcd peaaegu koheselt.<\/p>\n<p><\/p>\n<p><strong>Eriline t\u00e4nu\u00a0<\/strong>minu kolleegidele\u00a0<em>meeskonnast Adithya Mishrale<\/em>,\u00a0<em>Adithya Gaurile\u00a0<\/em>ja\u00a0<em><noindex><a rel=\"nofollow\" href=\"https:\/\/twitter.com\/s0ftvar\">Varun Malhotrale\u00a0<\/a><\/noindex><\/em>ajur\u00fcnnakute eest ja\u00a0<em>Dinkar Pandirile\u00a0<\/em>selle eest, et leidis meie l\u00f5ppp\u00e4ringus olulise vea, enne kui me sellega l\u00f5plikult h\u00fcvasti j\u00e4tsime!<\/p>\n<p>Allikas: <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.0.1 - 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. \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,\" \/>\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\/et\/blog\/administrirovanie\/istoriya-odnogo-sql-rassledovaniya\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.0.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"et_EE\" \/>\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. \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,\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/et\/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\udd47\u00dche SQL uurimise lugu | ProHoster","description":"Eelmise aasta detsembris sain huvitava veateate VWO tugimeeskonnalt. \u00dche anal\u00fc\u00fctilise aruande laadimisaeg suure ettev\u00f5tte kliendi jaoks tundus olema liiga pikk. Kuna see valdkond kuulus minu vastutusele, keskendusin ma kohe probleemi lahendamisele. Eelajaloo Selgitamaks, millest on jutt, r\u00e4\u00e4gin ma natuke VWO-st. See on platvorm,","canonical_url":"https:\/\/prohoster.info\/et\/blog\/administrirovanie\/istoriya-odnogo-sql-rassledovaniya","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"et_EE","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. \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,","og:url":"https:\/\/prohoster.info\/et\/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\/et\/wp-json\/wp\/v2\/posts\/35259","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/comments?post=35259"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/posts\/35259\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/media?parent=35259"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/categories?post=35259"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/tags?post=35259"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}