<div id="cnblogs_post_body" class="blogpost-body cnblogs-markdown"><p>遇到一個SQL執行很慢 SQL 以下:</p> <pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> ... <span class="hljs-keyword">FROM</span> tableA <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">time</span> >= <span class="hljs-number">1492044535</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">time</span> <= <span class="hljs-number">1492046335</span> <span class="hljs-keyword">GROUP</span> <span class="hljs-keyword">by</span> <span class="hljs-keyword">time</span>, sourceName, serverSite,clientSite;</code></pre> <p>SELECT 部分忽略沒寫,是由於一般SQL執行慢不會跟這部分有關係,至少我沒見過。</p> <p>該語句很是簡單,可是執行太慢。因此咱們看一下執行計劃</p> <p>執行計劃有幾個字段咱們比較關注:</p> <pre><code class="hljs css"><span class="hljs-selector-tag">type</span><span class="hljs-selector-pseudo">:range</span> <span class="hljs-selector-tag">possible_keys</span><span class="hljs-selector-pseudo">:time</span> <span class="hljs-selector-tag">key</span><span class="hljs-selector-pseudo">:time</span> <span class="hljs-selector-tag">extra</span><span class="hljs-selector-pseudo">:using</span> <span class="hljs-selector-tag">index</span> <span class="hljs-selector-tag">condition</span>; <span class="hljs-selector-tag">using</span> <span class="hljs-selector-tag">temporary</span>; <span class="hljs-selector-tag">using</span> <span class="hljs-selector-tag">filesort</span></code></pre> <p>type 表明鏈接類型。range是索引範圍掃描的時候顯示的類型。<br> possible_keys 和 keys 是可用的索引以及實際的索引<br> extra 比較關鍵,咱們詳細看一下這裏的信息:</p> <h1 id="filesort">filesort</h1> <p>是說在排序的時候,沒辦法使用索引。好比咱們這裏用的索引是time,但group by 是 time, sourceName, serverSite,clientSite。Mysql有一點很重要是會默認按照group by排序。</p> <pre><code class="hljs vbnet"><span class="hljs-keyword">group</span> <span class="hljs-keyword">by</span> time, sourceName, serverSite, clientSite </code></pre> <p>和</p> <pre><code class="hljs vbnet"><span class="hljs-keyword">order</span> <span class="hljs-keyword">by</span> time, sourceName, serverSite, clientSite</code></pre> <p>開銷其實區別不大。因此這裏排序不但要按照time 還要按照其它幾列</p> <h1 id="解決辦法">解決辦法</h1> <p>加order by null 這樣在group by的時候默認不排序,能夠去掉filesort。 但實際測試發現仍是慢,因此file sort不是性能關鍵。</p> <h1 id="using-tempoaray">using tempoaray</h1> <p>這裏是說在mysql執行過程當中產生了臨時表。這個操做比較耗時間。mysql的文檔列出了幾種會產生臨時表的語法,但和咱們這裏的狀況都不相符合。卻是mariadb的文檔,雖然不是很詳細,但說明了咱們的語句確實可能用到臨時表</p> <pre><code class="hljs vbnet">A temporary table <span class="hljs-keyword">is</span> created <span class="hljs-keyword">to</span> hold the result. This typically happens <span class="hljs-keyword">if</span> you are <span class="hljs-keyword">using</span> <span class="hljs-keyword">GROUP</span> <span class="hljs-keyword">BY</span>, <span class="hljs-keyword">DISTINCT</span> <span class="hljs-keyword">or</span> <span class="hljs-keyword">ORDER</span> <span class="hljs-keyword">BY</span>.</code></pre> <p>仔細分析一下也有道理,用索引查到數據後,你須要對這些數據分組。這個過程確定是在一個數據集上操做的,那麼這個數據集應該就是臨時表了。不想要這個數據集的辦法就是取消這個分組操做。咱們只須要create一個聯合索引</p> <pre><code class="hljs perl"><span class="hljs-keyword">time</span>,sourceName,serverSite,clientSite</code></pre> <p>這樣一個索引能夠經過time過濾,自然按照分組的順序排序,就不用臨時表了。</p> <p>同時能夠在執行語句中加個force index強制執行這個索引。<br> 這樣就沒有using temporary這個操做了</p> </div>css