{"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\/ro\/blog\/administrirovanie\/istoriya-odnogo-sql-rassledovaniya","title":{"rendered":"Povestea unei investiga\u021bii SQL","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>\u00cen decembrie anul trecut, am primit un raport interesant despre o eroare din partea echipei de suport VWO. Timpul de \u00eenc\u0103rcare al unuia dintre rapoartele analitice pentru un client corporativ mare p\u0103rea extrem de mare. Fiindc\u0103 aceasta este domeniul meu de responsabilitate, m-am concentrat imediat pe rezolvarea problemei.<\/p>\n<p><\/p>\n<h2>Povestea<\/h2>\n<p><\/p>\n<p>Pentru a fi clar despre ce este vorba, voi povesti pu\u021bin despre VWO. Este o platform\u0103 prin care putem lansa diferite campanii \u021bintite pe site-urile noastre: realizarea de experimente A\/B, urm\u0103rirea vizitatorilor \u0219i conversiilor, efectuarea de analize ale canalelor de v\u00e2nz\u0103ri, prezentarea h\u0103r\u021bilor de c\u0103ldur\u0103 \u0219i redarea \u00eenregistr\u0103rilor vizitelor.<\/p>\n<p><\/p>\n<p>Dar cel mai important aspect al platformei este elaborarea rapoartelor. Toate func\u021biile enumerate mai sus sunt interconectate. Iar pentru clien\u021bii corporativi, un volum mare de informa\u021bii ar fi fost pur \u0219i simplu inutil f\u0103r\u0103 o platform\u0103 puternic\u0103 care s\u0103 le prezinte \u00eentr-un format analitic.<\/p>\n<p><\/p>\n<p>Folosind platforma, po\u021bi efectua o cerere aleatorie pe un set mare de date. Iat\u0103 un exemplu simplu:<\/p>\n<p><\/p>\n<pre>Arat\u0103 toate clicurile de pe pagina \"abc.com\" \nDE LA &lt;data d1&gt; P\u00c2N\u0102 LA &lt;data d2&gt; \npentru persoanele care \na folosit Chrome SAU \n(au fost \u00een Europa \u0218I au folosit iPhone)<\/pre>\n<p><\/p>\n<p>Observa\u021bi operatorii booleani. Ace\u0219tia sunt disponibili pentru clien\u021bi \u00een interfa\u021ba cererii, pentru a face cereri oric\u00e2t de complexe pentru a ob\u021bine e\u0219antioane.<\/p>\n<p><\/p>\n<h2>Cerere lent\u0103<\/h2>\n<p><\/p>\n<p>Clientul despre care vorbim a \u00eencercat s\u0103 fac\u0103 ceva ce ar trebui s\u0103 func\u021bioneze rapid din instinct:<\/p>\n<p><\/p>\n<pre>Afi\u0219eaz\u0103 toate \u00eenregistr\u0103rile sesiunilor \npentru utilizatorii care au vizitat orice pagin\u0103 \ncu URL-ul care con\u021bine \"\\\/jobs\"<\/pre>\n<p><\/p>\n<p>Acest site avea un num\u0103r uria\u0219 de trafic, iar noi stocam peste un milion de URL-uri unice doar pentru el. \u0218i voiau s\u0103 g\u0103seasc\u0103 un model destul de simplu de URL, relevant pentru modelul lor de afaceri.<\/p>\n<p>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Investiga\u021bie preliminar\u0103<\/h2>\n<p><\/p>\n<p>S\u0103 vedem ce se \u00eent\u00e2mpl\u0103 \u00een baza de date. Iat\u0103 cererea SQL lent\u0103 de baz\u0103:<\/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>Iat\u0103 timpii:<\/p>\n<p><\/p>\n<pre>Timpul estimat: 1.480 ms\nTimpul de execu\u021bie: 1431924.650 ms<\/pre>\n<p><\/p>\n<p>Interogarea a parcurs 150 de mii de r\u00e2nduri. Planificatorul de interog\u0103ri a ar\u0103tat c\u00e2teva detalii interesante, dar f\u0103r\u0103 niciun punct evident de blocaj.<\/p>\n<p><\/p>\n<p>S\u0103 analiz\u0103m interogarea mai departe. Dup\u0103 cum se vede, aceasta face <code>JOIN<\/code> trei tabele:<\/p>\n<p><\/p>\n<ol>\n<li><strong>sessions<\/strong>: pentru a afi\u0219a informa\u021biile despre sesiune: browser, agent utilizator, \u021bar\u0103 \u0219i a\u0219a mai departe.<\/li>\n<li><strong>recording_data<\/strong>: URL-uri \u00eenregistrate, pagini, durata vizitelor<\/li>\n<li><strong>urls<\/strong>: pentru a evita duplicarea unor URL-uri extrem de mari, le stoc\u0103m \u00eentr-un tabel separat.<\/li>\n<\/ol>\n<p><\/p>\n<p>De asemenea, observa\u021bi c\u0103 toate tabelele noastre sunt deja \u00eemp\u0103r\u021bite pe <code>account_id<\/code>. Astfel, situa\u021bia \u00een care un singur cont foarte mare afecteaz\u0103 pe celelalte este exclus\u0103.<\/p>\n<p><\/p>\n<h2>\u00cen c\u0103utarea indiciilor<\/h2>\n<p><\/p>\n<p>La o examinare mai atent\u0103, vedem c\u0103 ceva \u00een interogarea specific\u0103 nu func\u021bioneaz\u0103 corect. Ar trebui s\u0103 ne uit\u0103m la aceast\u0103 linie:<\/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>Prima idee a fost c\u0103 poate din cauza <code>ILIKE<\/code> la toate aceste URL-uri lungi (avem peste 1,4 milioane de <strong>adreselor URL unice, colectate pentru acest cont) performan\u021ba ar putea fi afectat\u0103.\u00a0<\/strong>Dar, nu \u2014 asta nu este problema!<\/p>\n<p><\/p>\n<p>SELECT id FROM urls WHERE url ILIKE '%enterprise_customer.com\/jobs%';\n  id\n--------\n ...\n(198661 r\u00e2nduri)\n\nTimp: 5231.765 ms<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">Interogarea de c\u0103utare dup\u0103 \u0219ablon dureaz\u0103 doar 5 secunde. C\u0103utarea dup\u0103 \u0219ablon pe un milion de URL-uri unice nu este evident o problem\u0103.<\/code><\/pre>\n<p><\/p>\n<p>Urm\u0103torul suspect de pe list\u0103 \u2014 c\u00e2teva<\/p>\n<p><\/p>\n<p>. Poate utilizarea excesiv\u0103 a acestora a dus la \u00eencetinire? De obicei <code>JOIN<\/code>\u2018ele sunt cele mai evidente candida\u021bi pentru probleme de performan\u021b\u0103, dar nu am crezut c\u0103 cazul nostru este tipic. <code>JOIN<\/code>\u2018s sunt cei mai eviden\u021bi candida\u021bi pentru probleme de performan\u021b\u0103, dar nu am crezut c\u0103 cazul nostru este unul tipic.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">\u0218i acesta nu a fost cazul nostru.<\/code><\/pre>\n<p><\/p>\n<p>\u2018ele s-au dovedit a fi destul de rapide. <code>JOIN<\/code>\u2018s s-au dovedit a fi foarte rapide.<\/p>\n<p><\/p>\n<h2>Eram gata s\u0103 \u00eencep s\u0103 modific interogarea pentru a ob\u021bine orice \u00eembun\u0103t\u0103\u021biri posibile de performan\u021b\u0103. Cu echipa am dezvoltat 2 idei principale:<\/h2>\n<p><\/p>\n<p>Utiliza\u021bi EXISTS pentru subinterogarea URL-urilor<\/p>\n<p><\/p>\n<ul>\n<li><strong>: Vream s\u0103 verific\u0103m din nou dac\u0103 exist\u0103 probleme cu subinterogarea pentru URL-uri. Unul dintre modurile de a face acest lucru este de a folosi pur \u0219i simplu<\/strong>EXISTS <code>[START WITH \u2026] CONNECT BY<\/code>. <code>[START WITH \u2026] CONNECT BY<\/code> <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/functions-subquery.html#FUNCTIONS-SUBQUERY-EXISTS\">poate<\/a><\/noindex> \u00eembun\u0103t\u0103\u021be\u0219te semnificativ performan\u021ba, deoarece se \u00eencheie imediat dup\u0103 ce g\u0103se\u0219te o singur\u0103 linie \u00een func\u021bie de condi\u021bie.<\/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. Subinterogarea, c\u00e2nd este \u00eenvelit\u0103 \u00een\u00a0<code>[START WITH \u2026] CONNECT BY<\/code>, face totul super rapid. Urm\u0103toarea \u00eentrebare logic\u0103 este, de ce interogarea cu <code>JOIN<\/code>-urile \u0219i subinterogarea sunt rapide separat, dar \u00eencetinesc teribil \u00eempreun\u0103?<\/p>\n<p><\/p>\n<ul>\n<li><strong>Mut\u0103m subinterogarea \u00een CTE <\/strong>: dac\u0103 interogarea este rapid\u0103 de la sine, putem doar calcula mai \u00eent\u00e2i rezultatul rapid \u0219i apoi s\u0103-l oferim interog\u0103rii principale.<\/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>Dar \u0219i asta era \u00eenc\u0103 foarte lent.<\/p>\n<p><\/p>\n<h2>G\u0103sim vinovatul<\/h2>\n<p><\/p>\n<p>Toat\u0103 aceast\u0103 vreme, un detaliu mi-a tot trecut prin fa\u021ba ochilor, de care m\u0103 \u00eendep\u0103rtam constant. Dar, deoarece nu mai r\u0103m\u0103sese nimic altceva, am decis s\u0103 m\u0103 uit \u0219i la el. Vorbesc despre <code>&amp;&amp;<\/code> operator. P\u00e2n\u0103 acum <code>[START WITH \u2026] CONNECT BY<\/code> a \u00eembun\u0103t\u0103\u021bit performan\u021ba, <code>&amp;&amp;<\/code> a fost singurul factor comun r\u0103mas \u00een toate versiunile interog\u0103rii lente.<\/p>\n<p><\/p>\n<p>Privind la <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/9.1\/functions-array.html\">documenta\u021bie<\/a><\/noindex>, vedem c\u0103 <code>&amp;&amp;<\/code> este folosit atunci c\u00e2nd trebuie s\u0103 g\u0103sim elementele comune dintre dou\u0103 matrice.<\/p>\n<p><\/p>\n<p>\u00cen interogarea original\u0103, acesta este:<\/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>Ce \u00eenseamn\u0103 c\u0103 facem o c\u0103utare pe baz\u0103 de model pe adresele noastre, apoi g\u0103sim intersec\u021bia cu toate adresele cu \u00eenregistr\u0103ri comune. Este pu\u021bin confuz, deoarece \"urls\" aici nu se refer\u0103 la tabela care con\u021bine toate URL-urile, ci la coloana \"urls\" din tabela <code>recording_data<\/code>.<\/p>\n<p><\/p>\n<p>Cu \u00eendoieli cresc\u00e2nd cu privire la <code>&amp;&amp;<\/code>, am \u00eencercat s\u0103 le confirm \u00een planul de interogare generat de <code>EXPLAIN ANALYZE<\/code> (am avut deja un plan salvat, dar de obicei \u00eemi este mai convenabil s\u0103 experimentez \u00een SQL dec\u00e2t s\u0103 \u00eencerc s\u0103 \u00een\u021beleg opacit\u0103\u021bile planificatorilor de interog\u0103ri).<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">Filtru: ((urls &amp;&amp; ($0)::text[]) \u0218I (r_time &gt; '2018-12-17 12:17:23+00'::timestamp cu fus orar) \u0218I (r_time = '5'::double precision) \u0218I (num_of_pages &gt; 0))\n                           R\u00e2nduri eliminate de filtru: 52710<\/code><\/pre>\n<p><\/p>\n<p>A fost c\u00e2teva linii de filtre doar din <code>&amp;&amp;<\/code>. Ceea ce a \u00eensemnat c\u0103 aceast\u0103 opera\u021bie nu doar c\u0103 a fost costisitoare, dar a fost efectuat\u0103 de mai multe ori.<\/p>\n<p><\/p>\n<p>Am verificat asta, izol\u00e2nd condi\u021bia<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">SELECT 1\nFROM \n    acc_{account_id}.urls ca recordings_urls, \n    acc_{account_id}.recording_data_30 ca recording_data_30, \n    acc_{account_id}.sessions_30 ca 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>Aceast\u0103 interogare s-a executat lent. Deoarece <code>JOIN<\/code>-represent\u0103rile sunt rapide \u0219i subinterog\u0103rile sunt rapide, r\u0103m\u00e2ne doar <code>&amp;&amp;<\/code> operator.<\/p>\n<p><\/p>\n<p>Acesta este doar cheia opera\u021biei. Trebuie \u00eentotdeauna s\u0103 c\u0103ut\u0103m \u00een toat\u0103 tabela principal\u0103 a URL-urilor pentru a c\u0103uta dup\u0103 model \u0219i trebuie \u00eentotdeauna s\u0103 g\u0103sim intersec\u021biile. Nu putem c\u0103uta \u00een \u00eenregistr\u0103rile URL-urilor direct, deoarece sunt doar id-uri care se refer\u0103 la <code>urls<\/code>.<\/p>\n<p><\/p>\n<h2>Pe drumul c\u0103tre solu\u021bie,<\/h2>\n<p><\/p>\n<p><code>&amp;&amp;<\/code> \u00eencet, deoarece ambele seturi sunt enorme. Opera\u021bia va fi relativ rapid\u0103 dac\u0103 \u00eenlocuiesc <code>urls<\/code> pe <code>{ \"http:\/\/google.com\/\", \"http:\/\/wingify.com\/\" }<\/code>.<\/p>\n<p><\/p>\n<p>Am \u00eenceput s\u0103 c\u0103ut\u0103m o modalitate de a face \u00een Postgres intersec\u021bia mul\u021bimilor f\u0103r\u0103 a folosi <code>&amp;&amp;<\/code>, dar f\u0103r\u0103 prea mult succes.<\/p>\n<p><\/p>\n<p>\u00cen cele din urm\u0103, am decis pur \u0219i simplu s\u0103 rezolv\u0103m problema izolat: d\u0103-mi toate <code>urls<\/code> linii pentru care URL-ul se potrive\u0219te \u0219ablonului. F\u0103r\u0103 condi\u021bii suplimentare, aceasta va fi \u2014\u00a0<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">SELECT urls.url\nFROM \n\tacc_{account_id}.urls ca urls,\n\t(SELECT unnest(recording_data.urls) AS id) CA unrolled_urls\nWHERE\n\turls.id = unrolled_urls.id \u0218I\n\turls.url  ILIKE  '%jobs%'<\/code><\/pre>\n<p><\/p>\n<p>\u00cen loc de\u00a0<code>JOIN<\/code> sintax\u0103, am folosit pur \u0219i simplu o subinterogare \u0219i am desf\u0103cut <code>recording_data.urls<\/code> array-ul, pentru a putea aplica direct condi\u021bia \u00een <code>WHERE<\/code>.<\/p>\n<p><\/p>\n<p>Cel mai important aici este c\u0103 <code>&amp;&amp;<\/code> este folosit pentru a verifica dac\u0103 o \u00eenregistrare con\u021bine URL-ul corespunz\u0103tor. U\u0219or \u00eenclinat, se poate observa \u00een aceast\u0103 opera\u021bie mutarea prin elementele array-ului (sau r\u00e2ndurile tabelului) \u0219i oprirea la \u00eendeplinirea condi\u021biei (coresponden\u021bei). Nu-\u021bi aminte\u0219te de nimic? Aha, <code>[START WITH \u2026] CONNECT BY<\/code>.<\/p>\n<p><\/p>\n<p>Deoarece pe <code>recording_data.urls<\/code> poate fi referit din exterior contextului subinterog\u0103rii, c\u00e2nd se \u00eent\u00e2mpl\u0103 acest lucru, putem reveni la vechiul nostru prieten <code>[START WITH \u2026] CONNECT BY<\/code> \u0219i s\u0103-l \u00eenf\u0103\u0219ur\u0103m pe el \u00eentr-o subinterogare.<\/p>\n<p><\/p>\n<p>Combin\u00e2nd totul \u00eempreun\u0103, ob\u021binem interogarea final\u0103 optimizat\u0103:<\/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  (  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 EXISTS(\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>\u0218i timpul total de execu\u021bie <code>Timp: 1898.717 ms<\/code> E timpul s\u0103 s\u0103rb\u0103torim?!?<\/p>\n<p><\/p>\n<p>Nu at\u00e2t de repede! Mai \u00eent\u00e2i trebuie s\u0103 verific\u0103m corectitudinea. Am fost extrem de suspicios cu privire la <code>[START WITH \u2026] CONNECT BY<\/code> optimizare, deoarece aceasta schimb\u0103 logic\u0103 pentru o finalizare mai rapid\u0103. Trebuie s\u0103 ne asigur\u0103m c\u0103 nu am introdus o eroare neclar\u0103 \u00een interogare.<\/p>\n<p><\/p>\n<p>O verificare simpl\u0103 a fost executarea <code>count(*)<\/code> at\u00e2t pentru interog\u0103rile lente, c\u00e2t \u0219i pentru cele rapide, pe un num\u0103r mare de seturi de date diferite. Apoi, pentru un subset mic de date am verificat manual corectitudinea tuturor rezultatelor.<\/p>\n<p><\/p>\n<p>Toate verific\u0103rile au dat rezultate constant pozitive. Am reparat totul!<\/p>\n<p><\/p>\n<h2>\u00cenv\u0103\u021b\u0103minte Extrase<\/h2>\n<p><\/p>\n<p>Din aceast\u0103 poveste se pot extrage multe \u00eenv\u0103\u021b\u0103minte:<\/p>\n<p><\/p>\n<ol>\n<li>Planurile de interogare nu spun \u00eentreaga poveste, dar pot oferi indicii<\/li>\n<li>Principalele suspecte nu sunt \u00eentotdeauna adev\u0103ra\u021bii vinova\u021bi<\/li>\n<li>Interog\u0103rile lente pot fi divizate pentru a izola blocajele<\/li>\n<li>Nu toate optimiz\u0103rile sunt \u00een mod natural reduc\u0103toare<\/li>\n<li>Utilizare <code>EXIST<\/code>, acolo unde este posibil, poate duce la o cre\u0219tere semnificativ\u0103 a performan\u021bei<\/li>\n<\/ol>\n<p><\/p>\n<h2>Ie\u0219ire<\/h2>\n<p><\/p>\n<p>Am dus timpul de interogare de la ~24 de minute la 2 secunde \u2014 o cre\u0219tere semnificativ\u0103 a performan\u021bei! De\u0219i acest articol a ie\u0219it destul de lung, toate experimentele pe care le-am f\u0103cut s-au desf\u0103\u0219urat \u00eentr-o singur\u0103 zi \u0219i, estimativ, au durat \u00eentre 1,5 \u0219i 2 ore pentru optimiz\u0103ri \u0219i testare.<\/p>\n<p><\/p>\n<p>SQL este un limbaj minunat, dac\u0103 nu te temi de el, ci \u00eencerci s\u0103-l \u00een\u021belegi \u0219i s\u0103-l folose\u0219ti. Av\u00e2nd o bun\u0103 \u00een\u021belegere a modului \u00een care se execut\u0103 interog\u0103rile SQL, cum genereaz\u0103 baza de date planurile de interogare, cum func\u021bioneaz\u0103 indec\u0219ii \u0219i pur \u0219i simplu dimensiunea datelor cu care ai de-a face, vei putea s\u0103 excelezi \u00een optimizarea interog\u0103rilor. Nu mai pu\u021bin important, \u00eens\u0103, este s\u0103 continui s\u0103 \u00eencerci diverse abord\u0103ri \u0219i s\u0103 rezolvi gradual problema, g\u0103sind blocajele.<\/p>\n<p><\/p>\n<p>Cea mai bun\u0103 parte a ob\u021binerii unor astfel de rezultate este \u00eembun\u0103t\u0103\u021birea vizibil\u0103 \u0219i semnificativ\u0103 a vitezei \u2014 atunci c\u00e2nd un raport care anterior nu se \u00eenc\u0103rca deloc acum se \u00eencarc\u0103 aproape instantaneu.<\/p>\n<p><\/p>\n<p><strong>Mul\u021bumiri deosebite\u00a0<\/strong>colegilor mei\u00a0<em>din echipa lui Aditi Mishra<\/em>,\u00a0<em>Aditi Gaur\u00a0<\/em>\u0219i\u00a0<em><noindex><a rel=\"nofollow\" href=\"https:\/\/twitter.com\/s0ftvar\">Varun Malhotra\u00a0<\/a><\/noindex><\/em>pentru brainstorming \u0219i\u00a0<em>Dinkar Pandir\u00a0<\/em>pentru c\u0103 a g\u0103sit o eroare important\u0103 \u00een cererea noastr\u0103 final\u0103, \u00eenainte de a ne desp\u0103r\u021bi de ea!<\/p>\n<p>Sursa: <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.2.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\/ro\/blog\/administrirovanie\/istoriya-odnogo-sql-rassledovaniya\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"ro_RO\" \/>\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\/ro\/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\udd47Povestea unei investiga\u021bii SQL | ProHoster","description":"\u00cen decembrie anul trecut, am primit un raport interesant despre o eroare de la echipa de suport VWO. Timpul de \u00eenc\u0103rcare al unuia dintre rapoartele analitice pentru un mare client corporate p\u0103rea extrem de mare.","canonical_url":"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/istoriya-odnogo-sql-rassledovaniya","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"ro_RO","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\/ro\/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\/ro\/wp-json\/wp\/v2\/posts\/35259","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/comments?post=35259"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts\/35259\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/media?parent=35259"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/categories?post=35259"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/tags?post=35259"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}