{"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 uurimise lugu","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Eelmise aasta detsembris sain huvitava veaaruande VWO tugimeeskonnalt. \u00dche anal\u00fc\u00fcsiraporti laadimisaeg suurtele ettev\u00f5tte klientidele tundus olema \u00fclem\u00e4\u00e4ra pikk. Kuna see on minu vastutusala, keskendusin kohe probleemi lahendamisele.<\/p>\n<p><\/p>\n<h2>Eellugu<\/h2>\n<p><\/p>\n<p>Et selgem oleks, millest jutt k\u00e4ib, r\u00e4\u00e4gin veidi VWO-st. See on platvorm, mille abil saab k\u00e4ivitada erinevaid sihitud kampaaniaid oma veebilehtedel: l\u00e4bi viia A\/B katseid, j\u00e4lgida k\u00fclastajaid ja konversioone, anal\u00fc\u00fcsida m\u00fc\u00fcgivoolu, kuvada soojuskaarte ja esitada k\u00fclastuste salvestusi.<\/p>\n<p><\/p>\n<p>Aga k\u00f5ige t\u00e4htsam platvormi juures on aruannete koostamine. K\u00f5ik eelnevalt nimetatud funktsioonid on omavahel seotud. Ja ettev\u00f5tte klientide jaoks oleks tohutu informatsioonihulk lihtsalt kasutuks, kui see ei oleks korraliku anal\u00fc\u00fcsiplatvormi esitlemine.<\/p>\n<p><\/p>\n<p>Platvormi kasutades saab teha vaba p\u00e4ringu suurel andmekogumil. Siin on lihtne n\u00e4ide:<\/p>\n<p><\/p>\n<pre>Kuva k\u00f5ik kl\u00f5psud lehel \"abc.com\"\nKUNI &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 loogilisi operaatorite. Need on klientide jaoks p\u00e4ringute liideses, et luua keerulisemaid p\u00e4ringuid valikute saamiseks.<\/p>\n<p><\/p>\n<h2>Aeglane p\u00e4ring<\/h2>\n<p><\/p>\n<p>Client, mille kohta jutt k\u00e4ib, \u00fcritas teha midagi, mis peaks intuitiivselt toimuma kiiresti:<\/p>\n<p><\/p>\n<pre>Kuva k\u00f5ik sessioonide salvestused\nkasutajate jaoks, kes k\u00fclastasid mis tahes lehte,\nkus on url, mis sisaldab \"\\\/jobs\"<\/pre>\n<p><\/p>\n<p>Sellel veebisaidil oli tohutu liiklus ja me hoidsime \u00fcle miljoni ainulaadse URL-aadressi ainult selle jaoks. Ja nad soovisid leida \u00fcsna lihtsa url-malli, mis oleks seotud nende \u00e4ri mudeliga.<\/p>\n<p>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Eeluurimine<\/h2>\n<p><\/p>\n<p>Vaadakem, 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\u00e4ideviimise aeg: 1431924.650 ms<\/pre>\n<p><\/p>\n<p>P\u00e4ring h\u00f5lmas 150 000 rida. P\u00e4ringu planeerija n\u00e4itas paar huvitavat detaili, kuid ei mingit ilmselget kitsaskohta.<\/p>\n<p><\/p>\n<p>Uurime p\u00e4ringut edasi. Nagu n\u00e4ha, see teeb <code>JOIN<\/code> kolm tabelit:<\/p>\n<p><\/p>\n<ol>\n<li><strong>sessions<\/strong>: seansi teabe n\u00e4itamiseks: brauser, kasutajaagent, riik jne.<\/li>\n<li><strong>recording_data<\/strong>: salvestatud URLid, lehed, k\u00fclastuste kestus<\/li>\n<li><strong>urls<\/strong>: et v\u00e4ltida \u00e4\u00e4rmiselt suurte URLide dubleerimist, hoiame neid 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>. Nii on v\u00e4listatud olukord, kus \u00fche eriti suure konto t\u00f5ttu tekivad probleemid \u00fclej\u00e4\u00e4nutel.<\/p>\n<p><\/p>\n<h2>T\u00f5endite otsing<\/h2>\n<p><\/p>\n<p>L\u00e4hemal vaatlemisel n\u00e4eme, et konkreetse p\u00e4ringuga 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 v\u00f5ib-olla on selle t\u00f5ttu, et <code>ILIKE<\/code> k\u00f5ikide nende pikkade URLide puhul (meil on rohkem kui 1,4 miljonit <strong>unikaalset\u00a0<\/strong>URLi, mis on selle konto jaoks kogutud) j\u00f5udlus v\u00f5ib olla problemaatiline.<\/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 rida)\n\nAeg: 5231.765 ms<\/code><\/pre>\n<p><\/p>\n<p>Isegi mustriotsingu p\u00e4ring v\u00f5tab vaid 5 sekundit. Mustriotsing miljonis unikaalses URLis pole kindlasti probleem.<\/p>\n<p><\/p>\n<p>J\u00e4rgmine kahtlane isik nimekirjas \u2014 m\u00f5ned <code>JOIN<\/code>. V\u00f5ib-olla nende \u00fclem\u00e4\u00e4rane kasutamine viis aeglustumiseni? Tavalised <code>JOIN<\/code>'id' on k\u00f5ige ilmselgemad kandidaadid j\u00f5udlusprobleemide jaoks, kuid ma ei uskunud, 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 = 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 polnud samuti meie juhtum. <code>JOIN<\/code>'id' osutus \u00fcsna kiireks.<\/p>\n<p><\/p>\n<h2>Kitsendame kahtlusaluste ringi<\/h2>\n<p><\/p>\n<p>Olin valmis alustama p\u00e4ringu muutmist, et saavutada v\u00f5imalikult palju j\u00f5udluse parandusi. Meie meeskond t\u00f6\u00f6tas v\u00e4lja kaks peamist ideed:<\/p>\n<p><\/p>\n<ul>\n<li><strong>Kasutada EXISTS URL alamp\u00e4ringut<\/strong>: Soovisime veel kord kontrollida, kas URLide alamp\u00e4ringuga on probleeme. \u00dcks viis selle saavutamiseks 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\">v\u00f5ib<\/a><\/noindex> t\u00f5husalt parandada j\u00f5udlust, kuna see l\u00f5ppeb kohe, kui see leiab ainulaadse rea tingimuse alusel.<\/li>\n<\/ul>\n<p><\/p>\n<pre><code class=\"plaintext\">VALI\n\tcount(*) \nKUST \n    acc_{account_id}.urls kui recordings_urls,\n    acc_{account_id}.recording_data kui recording_data,\n    acc_{account_id}.sessions kui sessions\nKUS\n    recording_data.usp_id = sessions.usp_id\n    JA  (  1 = 1  )\n    JA sessions.referrer_id = recordings_urls.id\n    JA  (exists(select id from acc_{account_id}.urls where url  ILIKE '%enterprise_customer.com\/jobs%'))\n    JA r_time &gt; to_timestamp(1547585600)\n    JA r_time =5\n    JA recording_data.num_of_pages &gt; 0 ;\n count\n 32519\n(1 rida)\nAeg: 1636.637 ms<\/code><\/pre>\n<p><\/p>\n<p>Jah, alamk\u00fcsitlus, kui see on pakendatud\u00a0<code>EXISTS<\/code>, muudab k\u00f5ik super kiireks. J\u00e4rgmine loogiline k\u00fcsimus on, miks p\u00e4ringud koos <code>JOIN<\/code>-idega ja alamk\u00fcsitlus on eraldi kiiresti, kuid koos aeglustavad need kohutavalt?<\/p>\n<p><\/p>\n<ul>\n<li><strong>Viime alamk\u00fcsitluse CTE-sse <\/strong>: kui p\u00e4ring on iseenesest kiire, saame k\u00f5igepealt lihtsalt kiiresti tulemuse arvutada ja seej\u00e4rel anda selle p\u00f5hip\u00e4ringule<\/li>\n<\/ul>\n<p><\/p>\n<pre><code class=\"plaintext\">WITH matching_urls AS (\n    vali id::text from acc_{account_id}.urls where url ILIKE '%enterprise_customer.com\/jobs%'\n)\n\nVALI \n    count(*) FROM acc_{account_id}.urls kui recordings_urls, \n    acc_{account_id}.recording_data kui recording_data, \n    acc_{account_id}.sessions kui sessions,\n    matching_urls\nKUS \n    recording_data.usp_id = sessions.usp_id \n    JA  (  1 = 1  )  \n    JA sessions.referrer_id = recordings_urls.id\n    JA (urls &amp;&amp; array(VALI id from matching_urls)::text[])\n    JA r_time &gt; to_timestamp(1542585600) \n    JA r_time =5 \n    JA recording_data.num_of_pages &gt; 0;<\/code><\/pre>\n<p><\/p>\n<p>Kuid isegi see oli endiselt v\u00e4ga aeglane.<\/p>\n<p><\/p>\n<h2>Leiame s\u00fc\u00fcdlase<\/h2>\n<p><\/p>\n<p>Kogu selle aja silme ees vilkus \u00fcks pisiasi, millest ma pidevalt k\u00f5rvale t\u00f5ukasin. Kuid kuna ei j\u00e4\u00e4nud enam midagi muud, otsustasin sellele pilku heita. Ma r\u00e4\u00e4gin <code>&amp;&amp;<\/code> operaatorist. Seni <code>EXISTS<\/code> lihtsalt parandas j\u00f5udlust, <code>&amp;&amp;<\/code> oli ainus allesj\u00e4\u00e4nud \u00fchine tegur k\u00f5igis aeglase p\u00e4ringu versioonides.<\/p>\n<p><\/p>\n<p>Vaadates <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/9.1\/functions-array.html\">dokumentatsioon<\/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 see:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">JA  (  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>Mis t\u00e4hendab, et me teeme mustri p\u00f5hjal otsingu meie URLe, seej\u00e4rel leiame ristmiku k\u00f5ikide URL-idega, millel on \u00fchised kirjed. See on natuke segane, kuna 'urls' siin ei viita tabelile, kus on k\u00f5ik URL-id, vaid veerg 'urls' tabelis <code>recording_data<\/code>.<\/p>\n<p><\/p>\n<p>Seoses suureneva kahtlusega <code>&amp;&amp;<\/code>, \u00fcritasin leida kinnitust nendele k\u00fcsimustele genereeritud p\u00e4ringu plaanis. <code>EXPLAIN ANALYZE<\/code> (mul on juba olnud salvestatud plaan, kuid tavaliselt on mul mugavam eksperimentida SQL-is kui proovida aru saada p\u00e4ringute optimeerijate l\u00e4bipaistmatust).<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">Filter: ((urls &amp;&amp; ($0)::text[]) JA (r_time &gt; '2018-12-17 12:17:23+00'::timestamp with time zone) JA (r_time = '5'::double precision) JA (num_of_pages &gt; 0))\n                           Ridu eemaldatud filtri kaudu: 52710<\/code><\/pre>\n<p><\/p>\n<p>Seal oli mitu filtririda ainult <code>&amp;&amp;<\/code>. Mis t\u00e4hendas, et see operatsioon oli mitte ainult kulukas, vaid j\u00f5udis ka mitu korda toime.<\/p>\n<p><\/p>\n<p>Kontrollisin seda, isolerides 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 k\u00e4idi aeglaselt. Kuna <code>JOIN<\/code>-id on kiired ja alam-p\u00e4ringud on kiired, j\u00e4i \u00fcle ainult <code>&amp;&amp;<\/code> operaator.<\/p>\n<p><\/p>\n<p>Aga see on ainult see peamine operatsioon. Me peame alati otsima kogu p\u00f5hilaudade URL-addresside kaudu, et otsida mallide j\u00e4rgi ja me peame alati leidma ristumisi. Me ei saa otsida URL-ide salvestiste kaudu otse, sest need on lihtsalt ID, mis viitavad <code>urls<\/code>.<\/p>\n<p><\/p>\n<h2>Teel lahendusele<\/h2>\n<p><\/p>\n<p><code>&amp;&amp;<\/code> aeglane, kuna m\u00f5lemad kogumid on suured. Operatsioon oleks suhteliselt kiire, kui ma asendan <code>urls<\/code> . Tundub, et <code>{ \"http:\/\/google.com\/\", \"http:\/\/wingify.com\/\" }<\/code>.<\/p>\n<p><\/p>\n<p>Hakkasin otsima viisi, kuidas teha Postgresis kogumite ristumist ilma <code>&amp;&amp;<\/code>, kuid ilma eriliste edusammudeta.<\/p>\n<p><\/p>\n<p>L\u00f5puks otsustasime lihtsalt lahendada probleemi isoleeritult: anna mulle k\u00f5ik <code>urls<\/code> read, mille URL vastab mustrile. Ilma lisatingimusteta 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 JA\n\turls.url ILIKE '%jobs%'<\/code><\/pre>\n<p><\/p>\n<p>Asenda\u00a0<code>JOIN<\/code> s\u00fcntaksis kasutasin lihtsalt alam-p\u00e4ringut ja avasin <code>recording_data.urls<\/code> massiiv, et saaks otse rakendada tingimust <code>KUS<\/code>.<\/p>\n<p><\/p>\n<p>Siin on k\u00f5ige olulisem see, et <code>&amp;&amp;<\/code> kasutatakse, et kontrollida, kas antud salvestis sisaldab vastavat URL- \u0430\u0434\u0440\u0435\u0441\u0430. Veidi t\u00f5mmates v\u00f5ib n\u00e4ha, kuidas selles operatsioonis liikuda massiivi elementide (v\u00f5i tabeli ridade) vahel ja peatuda, kui toimub tingimus (vastavus). Kas midagi ei meenuta? Ah, <code>EXISTS<\/code>.<\/p>\n<p><\/p>\n<p>Kuna <code>recording_data.urls<\/code> v\u00f5ib viidata alt konteksti alam-p\u00e4ringu kontekstis, kui see juhtub, saame tagasi p\u00f6\u00f6rduda meie vanade s\u00f5prade poole <code>EXISTS<\/code> ja \u00fcmbritseda seda alam-p\u00e4ringut.<\/p>\n<p><\/p>\n<p>Kokku sidudes saame me l\u00f5puks optimeeritud p\u00e4ringu:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">VALI \n    count(*) \nKUSTA \n    acc_{account_id}.urls kui recordings_urls, \n    acc_{account_id}.recording_data kui recording_data, \n    acc_{account_id}.sessions kui sessions \nKUS \n    recording_data.usp_id = sessions.usp_id \n    JA  (  1 = 1  )  \n    JA sessions.referrer_id = recordings_urls.id \n    JA r_time &gt; to_timestamp(1542585600) \n    JA r_time =5 \n    JA recording_data.num_of_pages &gt; 0\n    JA EXITS(\n        VALI urls.url\n        KUSTA \n            acc_{account_id}.urls kui urls,\n            (VALI unnest(urls) AS rec_url_id KUSTA acc_{account_id}.recording_data) \n            KUI unrolled_urls\n        KUS\n            urls.id = unrolled_urls.rec_url_id JA\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 aeg t\u00e4histamiseks?!?<\/p>\n<p><\/p>\n<p>\u00c4ra nii kiiresti! Esiteks peame kontrollima \u00f5igsust. Ma olin \u00e4\u00e4rmiselt kahtlev <code>EXISTS<\/code> optimeerimise osas, kuna see muudab loogikat varasemaks l\u00f5petamiseks. Me peame olema kindlad, et me ei ole lisanud n\u00e4htamatut viga p\u00e4ringusse.<\/p>\n<p><\/p>\n<p>Lihtne kontroll seisnes <code>count(*)<\/code> ja aeglastes ja kiiretes p\u00e4ringutes erinevate andmekogumite jaoks. Seej\u00e4rel kontrollisin v\u00e4ikese andmekogumi puhul k\u00f5iki tulemusi k\u00e4sitsi.<\/p>\n<p><\/p>\n<p>K\u00f5ik kontrollid andsid stabiilselt positiivseid tulemusi. Me oleme k\u00f5ik korda teinud!<\/p>\n<p><\/p>\n<h2>T\u00f5mmatud \u00d5ppetunnid<\/h2>\n<p><\/p>\n<p>Sellest loost saab palju \u00f5ppetunde:<\/p>\n<p><\/p>\n<ol>\n<li>K\u00fcsi plaanid ei r\u00e4\u00e4gi kogu lugu, kuid v\u00f5ivad anda vihjeid<\/li>\n<li>Peamised kahtlusalused ei ole alati t\u00f5elised s\u00fc\u00fcdlased<\/li>\n<li>Aeglaseid p\u00e4ringuid saab jagada kitsaste kohtade isoleerimiseks<\/li>\n<li>K\u00f5ik optimeerimised ei ole loomulikult reduktiivsed<\/li>\n<li>Kasutamine <code>EXIST<\/code>, kus see on v\u00f5imalik, v\u00f5ib viia drastilise j\u00f5udluse kasvuni<\/li>\n<\/ol>\n<p><\/p>\n<h2>Kokkuv\u00f5te<\/h2>\n<p><\/p>\n<p>Me liigutasime p\u00e4ringu aega ~24 minutist 2 sekundini - \u00fcsna m\u00e4rkimisv\u00e4\u00e4rne j\u00f5udluse kasv! Kuigi see artikkel on suur, toimusid k\u00f5ik eksperimendid \u00fche p\u00e4eva jooksul ja hinnanguliselt kulus optimeerimise ja testimise jaoks 1,5\u20132 tundi.<\/p>\n<p><\/p>\n<p>SQL on imeline keel, kui mitte karta seda, vaid p\u00fc\u00fcda aru saada ja kasutada. Hea arusaam sellest, kuidas SQL-p\u00e4ringuid t\u00f6\u00f6tatakse, kuidas andmebaas genereerib plaanid, kuidas indeksid t\u00f6\u00f6tavad ja lihtsalt andmete suurusest, millega on tegemist, aitab teil p\u00e4ringute optimeerimisel v\u00e4ga h\u00e4sti edasi j\u00f5uda. Samuti on oluline j\u00e4tkata erinevate l\u00e4henemiste proovimist ja aeglaselt probleemi lahendamist kitsaste kohtade leidmiseks.<\/p>\n<p><\/p>\n<p>Parim osa sarnaste tulemuste saavutamisel on silmapaistev n\u00e4htav kiiruset\u00f5us \u2014 kui aruanne, mis varem isegi ei laadinud, laadib n\u00fc\u00fcd peaaegu koheselt.<\/p>\n<p><\/p>\n<p><strong>Eriline t\u00e4nu\u00a0<\/strong>minu kolleegidele\u00a0<em>tiimist Aditya Mishra<\/em>,\u00a0<em>Aditya Gaur\u00a0<\/em>ja\u00a0<em><noindex><a rel=\"nofollow\" href=\"https:\/\/twitter.com\/s0ftvar\">Varun Malhotra\u00a0<\/a><\/noindex><\/em>ajur\u00fcnnaku ja\u00a0<em>Dinkar Pandirile\u00a0<\/em>selle eest, et leidis meie l\u00f5pp-p\u00e4ringus olulise vea, enne kui me selle l\u00f5plikult l\u00f5petasime!<\/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.1.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.\" \/>\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.1.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.\" \/>\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 ajalugu | ProHoster","description":"Eelmise aasta detsembris sain tosupport VWO meeskonnalt huvitava veaaruande. \u00dche anal\u00fc\u00fctilise aruande laadimisaeg suure ettev\u00f5tte kliendi jaoks tundus \u00fclem\u00e4\u00e4ra pikk.","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.","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}]}}