{"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\/it\/blog\/administrirovanie\/istoriya-odnogo-sql-rassledovaniya","title":{"rendered":"La storia di un'indagine SQL","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Lo scorso dicembre ho ricevuto un interessante rapporto di errore dal team di supporto VWO. Il tempo di caricamento di uno dei rapporti analitici per un grande cliente aziendale sembrava eccessivo. Poich\u00e9 questa \u00e8 una mia responsabilit\u00e0, mi sono subito concentrato sulla risoluzione del problema.<\/p>\n<p><\/p>\n<h2>Contesto<\/h2>\n<p><\/p>\n<p>Per chiarire di cosa stiamo parlando, voglio dire brevemente qualcosa su VWO. \u00c8 una piattaforma che consente di avviare diverse campagne mirate sui propri siti: condurre esperimenti A\/B, monitorare i visitatori e le conversioni, analizzare il funnel di vendita, visualizzare le heatmap e riprodurre le registrazioni delle visite.<\/p>\n<p><\/p>\n<p>Ma la cosa pi\u00f9 importante della piattaforma \u00e8 la creazione di rapporti. Tutte le funzioni sopra elencate sono interconnesse. E per i clienti aziendali, un'enorme quantit\u00e0 di informazioni sarebbe semplicemente inutile senza una piattaforma potente in grado di presentarle in modo analitico.<\/p>\n<p><\/p>\n<p>Utilizzando la piattaforma, \u00e8 possibile effettuare una richiesta arbitraria su un grande set di dati. Ecco un semplice esempio:<\/p>\n<p><\/p>\n<pre>Mostra tutti i click sulla pagina \"abc.com\"\nDAL &lt;data d1&gt; A &lt;data d2&gt;\nper le persone che\nhanno usato Chrome O\n(sono stati in Europa E hanno usato iPhone)<\/pre>\n<p><\/p>\n<p>Fai attenzione agli operatori booleani. Sono disponibili per i clienti nell'interfaccia di query, per creare query di qualsiasi complessit\u00e0 per ottenere i campioni.<\/p>\n<p><\/p>\n<h2>Richiesta lenta<\/h2>\n<p><\/p>\n<p>Il cliente in questione ha tentato di fare qualcosa che intuitivamente dovrebbe funzionare rapidamente:<\/p>\n<p><\/p>\n<pre>Mostra tutti i registri delle sessioni\nper gli utenti che hanno visitato qualsiasi pagina\ncon un URL che contiene \"\/jobs\"<\/pre>\n<p><\/p>\n<p>Su questo sito c'era un'enorme quantit\u00e0 di traffico, e conservavamo oltre un milione di URL unici solo per esso. E volevano trovare un modello di URL abbastanza semplice, relativo al loro modello di business.<\/p>\n<p>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Indagine preliminare<\/h2>\n<p><\/p>\n<p>Diamo un'occhiata a cosa sta succedendo nel database. Di seguito \u00e8 riportata la query SQL lenta originale:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">SELEZIONA \n    count(*) \nDA \n    acc_{account_id}.urls AS recordings_urls, \n    acc_{account_id}.recording_data AS recording_data, \n    acc_{account_id}.sessions AS sessions \nDOVE \n    recording_data.usp_id = sessions.usp_id \n    E sessions.referrer_id = recordings_urls.id \n    E  (  urls &amp;&amp;  array(select id from acc_{account_id}.urls where url  ILIKE  '%enterprise_customer.com\/jobs%')::text[]   ) \n    E r_time &gt; to_timestamp(1542585600) \n    E r_time = 5 \n    E recording_data.num_of_pages &gt; 0 ;<\/code><\/pre>\n<p><\/p>\n<p>Ecco i tempi:<\/p>\n<p><\/p>\n<pre>Tempo previsto: 1.480 ms\nTempo di esecuzione: 1431924.650 ms<\/pre>\n<p><\/p>\n<p>La query ha esaminato 150 mila righe. Il pianificatore ha mostrato un paio di dettagli interessanti, ma nessun collo di bottiglia evidente.<\/p>\n<p><\/p>\n<p>Esploriamo ulteriormente la query. Come si vede, essa fa riferimento <code>JOIN<\/code> a tre tabelle:<\/p>\n<p><\/p>\n<ol>\n<li><strong>sessioni<\/strong>: per mostrare informazioni sulla sessione: browser, user agent, paese e cos\u00ec via.<\/li>\n<li><strong>recording_data<\/strong>: url registrati, pagine, durata delle visite<\/li>\n<li><strong>urls<\/strong>: per evitare la duplicazione di url estremamente grandi, li conserviamo in una tabella separata.<\/li>\n<\/ol>\n<p><\/p>\n<p>Si noti inoltre che tutte le nostre tabelle sono gi\u00e0 suddivise per <code>account_id<\/code>. In questo modo, si esclude la possibilit\u00e0 che a causa di un account particolarmente grande sorgano problemi per gli altri.<\/p>\n<p><\/p>\n<h2>In cerca di indizi<\/h2>\n<p><\/p>\n<p>Dopo un'attenta analisi, notiamo che c'\u00e8 qualcosa di strano nella richiesta specifica. Vale la pena esaminare questa riga:<\/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>La prima idea \u00e8 stata che forse, a causa di <code>ILIKE<\/code> su tutti questi URL lunghi (abbiamo oltre 1,4 milioni di <strong>unici\u00a0<\/strong>URL raccolti per questo account) le prestazioni potrebbero risentirne.<\/p>\n<p><\/p>\n<p>Ma no \u2014 non \u00e8 questo il problema!<\/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 righe)\n\nTempo: 5231.765 ms<\/code><\/pre>\n<p><\/p>\n<p>La ricerca con il modello richiede solo 5 secondi. La ricerca del modello su un milione di URL unici non sembra essere un problema.<\/p>\n<p><\/p>\n<p>Il prossimo sospetto in lista sono alcuni <code>JOIN<\/code>. Forse il loro uso eccessivo ha portato a rallentamenti? Di solito <code>JOIN<\/code>Le righe sono i candidati pi\u00f9 evidenti ai problemi di prestazioni, ma non credevo che il nostro caso fosse tipico.<\/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 riga)\n\nTempo: 147.851 ms<\/code><\/pre>\n<p><\/p>\n<p>E questo non era nemmeno il nostro caso. <code>JOIN<\/code>Le righe si sono rivelate piuttosto veloci.<\/p>\n<p><\/p>\n<h2>Ristabiliamo il gruppo dei sospettati<\/h2>\n<p><\/p>\n<p>Ero pronto a modificare la query per ottenere qualsiasi possibile miglioramento delle prestazioni. Insieme al team, abbiamo sviluppato 2 idee principali:<\/p>\n<p><\/p>\n<ul>\n<li><strong>Utilizzare EXISTS per la sottoquery URL<\/strong>: Volevamo controllare nuovamente se ci fossero problemi con la sottoquery per gli URL. Un modo per farlo \u00e8 semplicemente usare <code>EXISTS<\/code>. <code>EXISTS<\/code> <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/functions-subquery.html#FUNCTIONS-SUBQUERY-EXISTS\">pu\u00f2<\/a><\/noindex> per migliorare notevolmente le prestazioni poich\u00e9 termina immediatamente, non appena trova la prima riga che soddisfa la condizione.<\/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>S\u00ec. La sottoquery, quando \u00e8 avvolta in\u00a0<code>EXISTS<\/code>, rende tutto super veloce. La prossima domanda logica \u00e8 perch\u00e9 la query con <code>JOIN<\/code>-la e la sottoquery siano veloci separatamente, ma rallentino terribilmente insieme?<\/p>\n<p><\/p>\n<ul>\n<li><strong>Spostiamo la sottoquery in CTE <\/strong>: se la richiesta \u00e8 veloce di per s\u00e9, possiamo semplicemente calcolare prima il risultato rapido e poi fornirlo alla richiesta 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>Ma anche questo era ancora molto lento.<\/p>\n<p><\/p>\n<h2>Troviamo il colpevole<\/h2>\n<p><\/p>\n<p>Per tutto il tempo davanti ai miei occhi splendeva un piccolo dettaglio, da cui mi tenevo sempre a distanza. Ma poich\u00e9 non c'era pi\u00f9 nulla da perdere, ho deciso di dare un'occhiata anche a quello. Sto parlando di <code>&amp;&amp;<\/code> l'operatore. Finora <code>EXISTS<\/code> ha semplicemente migliorato le prestazioni, <code>&amp;&amp;<\/code> era l'unico fattore comune rimasto in tutte le versioni della richiesta lenta.<\/p>\n<p><\/p>\n<p>Guardando a <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/9.1\/functions-array.html\">documentazione<\/a><\/noindex>, vediamo che <code>&amp;&amp;<\/code> si usa quando \u00e8 necessario trovare elementi comuni tra due array.<\/p>\n<p><\/p>\n<p>Nella richiesta originale \u00e8:<\/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>Cosa significa che facciamo una ricerca per modello sui nostri URL e poi troviamo l'intersezione con tutti gli URL che hanno voci comuni. \u00c8 un po' confuso, poich\u00e9 \"urls\" qui non si riferisce a una tabella contenente tutti gli URL, ma a una colonna \"urls\" nella tabella. <code>recording_data<\/code>.<\/p>\n<p><\/p>\n<p>Con l'aumento dei sospetti riguardo <code>&amp;&amp;<\/code>, ho cercato di trovare loro conferma nel piano di query generato <code>EXPLAIN ANALYZE<\/code> (avevo gi\u00e0 un piano salvato, ma di solito preferisco sperimentare in SQL piuttosto che cercare di capire le opacit\u00e0 dei pianificatori di query).<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">Filtro: ((urls &amp;&amp; ($0)::text[]) E (r_time &gt; '2018-12-17 12:17:23+00'::timestamp with time zone) E (r_time = '5'::double precision) E (num_of_pages &gt; 0))\n                           Righe rimosse dal filtro: 52710<\/code><\/pre>\n<p><\/p>\n<p>C'erano alcune righe di filtri solo da <code>&amp;&amp;<\/code>. Il che significava che questa operazione non solo era costosa, ma veniva eseguita pi\u00f9 volte.<\/p>\n<p><\/p>\n<p>L'ho verificato isolando la condizione<\/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>Questa query veniva eseguita lentamente. Poich\u00e9 <code>JOIN<\/code>-i sono veloci e i sottoquery sono veloci, restava solo <code>&amp;&amp;<\/code> operatore.<\/p>\n<p><\/p>\n<p>Ma questa \u00e8 l'operazione chiave. Dobbiamo sempre cercare in tutta la tabella principale degli URL per trovare secondo il modello e dobbiamo sempre trovare le intersezioni. Non possiamo cercare direttamente nei record degli URL, perch\u00e9 sono solo ID che fanno riferimento a <code>urls<\/code>.<\/p>\n<p><\/p>\n<h2>Sulla strada verso la soluzione<\/h2>\n<p><\/p>\n<p><code>&amp;&amp;<\/code> lento, perch\u00e9 entrambi i set sono enormi. L'operazione sar\u00e0 relativamente veloce se sostituisco <code>urls<\/code> con <code>{ \"http:\/\/google.com\/\", \"http:\/\/wingify.com\/\" }<\/code>.<\/p>\n<p><\/p>\n<p>Ho iniziato a cercare un modo per ottenere l'intersezione di insiemi in Postgres senza usare <code>&amp;&amp;<\/code>, ma senza molto successo.<\/p>\n<p><\/p>\n<p>Alla fine, abbiamo deciso di risolvere il problema in modo isolato: dammi tutte le <code>urls<\/code> stringhe, per le quali l'URL corrisponde al modello. Senza ulteriori condizioni sar\u00e0 &#8212;\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>Invece di\u00a0<code>JOIN<\/code> sintassi ho semplicemente usato una sottoquery e ho espanso <code>recording_data.urls<\/code> array, cos\u00ec potevo applicare direttamente la condizione in <code>DOVE<\/code>.<\/p>\n<p><\/p>\n<p>La cosa pi\u00f9 importante qui \u00e8 che <code>&amp;&amp;<\/code> viene utilizzato per controllare se questa voce contiene l'URL corrispondente. Se si guarda attentamente, si pu\u00f2 notare che in questa operazione avviene un attraversamento degli elementi dell'array (o delle righe della tabella) e ci si ferma al soddisfacimento della condizione (di corrispondenza). Ti ricorda qualcosa? Ah, <code>EXISTS<\/code>.<\/p>\n<p><\/p>\n<p>Poich\u00e9 su <code>recording_data.urls<\/code> si pu\u00f2 fare riferimento al di fuori del contesto della sottoquery, quando ci\u00f2 accade, possiamo tornare al nostro vecchio amico <code>EXISTS<\/code> e avvolgerlo attorno alla sottoquery.<\/p>\n<p><\/p>\n<p>Unendo tutto insieme, otteniamo la query finale ottimizzata:<\/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>E il tempo di esecuzione finale <code>Time: 1898.717 ms<\/code> \u00c8 ora di festeggiare?!?<\/p>\n<p><\/p>\n<p>Non cos\u00ec in fretta! Prima bisogna verificare la correttezza. Ero estremamente sospettoso riguardo <code>EXISTS<\/code> l'ottimizzazione, poich\u00e9 cambia la logica per una conclusione pi\u00f9 precoce. Dobbiamo assicurarci di non aver introdotto errori non evidenti nella query.<\/p>\n<p><\/p>\n<p>Una semplice verifica consisteva nell'eseguire <code>count(*)<\/code> sia su query lente che veloci per un gran numero di diversi set di dati. Successivamente, per un piccolo sottoinsieme di dati, ho controllato manualmente la correttezza di tutti i risultati.<\/p>\n<p><\/p>\n<p>Tutti i controlli hanno dato risultati costantemente positivi. Abbiamo risolto tutto!<\/p>\n<p><\/p>\n<h2>Lezioni Apprese<\/h2>\n<p><\/p>\n<p>Da questa storia si possono trarre molte lezioni:<\/p>\n<p><\/p>\n<ol>\n<li>I piani delle query non raccontano tutta la storia, ma possono offrire indizi<\/li>\n<li>I principali sospetti non sono sempre i veri colpevoli<\/li>\n<li>Le query lente possono essere suddivise per isolare i colli di bottiglia<\/li>\n<li>Non tutte le ottimizzazioni sono di natura riduttiva<\/li>\n<li>L'utilizzo di <code>EXIST<\/code>, dove possibile, pu\u00f2 portare a un aumento notevole delle prestazioni<\/li>\n<\/ol>\n<p><\/p>\n<h2>Risultato<\/h2>\n<p><\/p>\n<p>Siamo passati da un tempo di query di circa 24 minuti a 2 secondi \u2014 un notevole incremento di prestazioni! Anche se questo articolo \u00e8 lungo, tutti gli esperimenti che abbiamo condotto si sono svolti in un giorno e, stimando, hanno richiesto da 1,5 a 2 ore per ottimizzazioni e test.<\/p>\n<p><\/p>\n<p>SQL \u00e8 un linguaggio straordinario, se non lo si teme, ma si cerca di comprenderlo e utilizzarlo. Con una buona comprensione di come vengono eseguite le query SQL, di come il database genera i piani di query, di come funzionano gli indici e delle dimensioni dei dati con cui si ha a che fare, \u00e8 possibile eccellere nell'ottimizzazione delle query. \u00c8 altrettanto importante, per\u00f2, continuare a provare diversi approcci e risolvere lentamente i problemi individuando i colli di bottiglia.<\/p>\n<p><\/p>\n<p>La parte migliore nel raggiungere risultati simili \u00e8 il notevole miglioramento visibile della velocit\u00e0 di esecuzione: quando un report che prima non si caricava nemmeno ora si apre quasi istantaneamente.<\/p>\n<p><\/p>\n<p><strong>Un ringraziamento speciale\u00a0<\/strong>ai miei colleghi\u00a0<em>del team Aditya Mishra<\/em>,\u00a0<em>Aditya Gaur\u00a0<\/em>e\u00a0<em><noindex><a rel=\"nofollow\" href=\"https:\/\/twitter.com\/s0ftvar\">Varun Malhotra\u00a0<\/a><\/noindex><\/em>per il brainstorming e\u00a0<em>Dinkar Pandir\u00a0<\/em>per aver trovato un errore importante nella nostra query finale, prima che ci dicessimo addio definitivamente!<\/p>\n<p>Fonte: <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\/it\/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=\"it_IT\" \/>\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\/it\/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\udd47Storia di un'indagine SQL | ProHoster","description":"A dicembre dello scorso anno ho ricevuto un interessante rapporto di errore dal team di supporto di VWO. Il tempo di caricamento di uno dei report analitici per un grande cliente aziendale sembrava eccessivamente lungo. Poich\u00e9 questa \u00e8 una delle mie responsabilit\u00e0, mi sono subito concentrato sulla risoluzione del problema. Contesto Per capire di cosa si tratta, parler\u00f2 brevemente di VWO. Si tratta di una piattaforma,","canonical_url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/istoriya-odnogo-sql-rassledovaniya","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"it_IT","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\/it\/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\/it\/wp-json\/wp\/v2\/posts\/35259","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/comments?post=35259"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/35259\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media?parent=35259"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/categories?post=35259"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/tags?post=35259"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}