Mysql

MySQL 是將整行載入到記憶體中,還是僅載入 WHERE、ORDER BY 和 GROUP BY 中使用的列?

  • April 12, 2016

我有一個表不是很大的行(在 100ks 範圍內),但它包含很多大小非常大的原始數據。儘管行數相對較少,但大約為 1.5GB。

因此,了解 MySQL 是否將整行載入到記憶體中,或者僅在執行查詢時將 WHERE、ORDER BY 和 GROUP BY 中使用的列和索引以及最後的其餘列載入到記憶體中是非常重要的?

一個範例查詢:

SELECT HugeDataTable.*, Table2.Name
FROM Table1
LEFT JOIN Table2 ON Table1.`ID` = Table2.`Table1ID` 
LEFT JOIN HugeDataTable FORCE INDEX(RowOrder) ON Table2.`ID` = HugeDataTable.`Table2ID` 
WHERE HugeDataTable.Category = 5
AND HugeDataTable.RowOrder >10000 AND HugeDataTable.ID <> "h4324h534"
ORDER BY HugeDataTable.`RowOrder` DESC LIMIT 18 ;

使用 Explain SELECT,我發現 MySQL 每個查詢掃描大約 70k 行。查詢相當快,但我不確定它是否是由於行記憶體,因為我無法模擬伺服器上的繁重負載。

所以,我的問題是,在查詢將結果限制為 18 行之後,是否會載入包含大量原始數據的列,從而最終只載入所需的少量原始數據?

或者它們會在限制之前載入,因此在限制之前載入大約 1GB 的數據的 70k 行?如果是後一種情況,可以採取什麼措施來防止這種情況發生,因為伺服器只有 1GB 的 RAM。

**編輯:**我添加了解釋。

id  select_type  table          type    possible_keys                       key               key_len  ref                           rows   Extra                     
1   SIMPLE       HugeDataTable  range   Table2ID,Category,RowOrder          RowOrder          9                                      49591  Using where               
1   SIMPLE       Table2         eq_ref  PRIMARY                             PRIMARY           10       const,HugeDataTable.Table2ID  1      Using where; Using index  
1   SIMPLE       Table1         ref     PRIMARY                             PRIMARY           2        Table2.Table1ID               1    

因為它失去了,我假設您的查詢執行計劃顯示了對原始數據表的全掃描。如果是這種情況,那麼您的整個行將被載入到記憶體中(包括原始列),這顯然是不行的。

避免這種情況的最簡單方法是在過濾列上創建索引,以便查詢先掃描索引,並且只有當該行是您的結果集的候選時,才會到達表並將其載入到記憶體中.

來自評論討論:

查詢執行速度很快,主要是因為索引(因此刪除它時性能很慢)……但是您的行仍然完全載入。如您所想,只有部分行進入記憶體,但這並不意味著只有部分行被載入。這裡的技巧是索引只指向那些相關的行。您正在使用帶有 “>” 運算符的索引,這會導致範圍掃描,因此可能會引用比您需要/獲取的行更多的行。

您可以嘗試更早地應用 18 限制,而不是在查詢結束時。或者您可以創建一個只有原始列和第一個表的外鍵的新表。在查詢的最後連結來自第一個表的結果。但請記住,如果要對行進行排序,並ORDER BY在連接兩個表後執行,它仍然會使用載入到記憶體中的原始數據執行排序。

在加入原始表之前嘗試對主表的行進行排序。如果主表引導連接,那麼您也應該在連接之後對行進行排序。

引用自:https://dba.stackexchange.com/questions/56757