MySQL 是將整行載入到記憶體中,還是僅載入 WHERE、ORDER BY 和 GROUP BY 中使用的列?
我有一個表不是很大的行(在 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
在連接兩個表後執行,它仍然會使用載入到記憶體中的原始數據執行排序。在加入原始表之前嘗試對主表的行進行排序。如果主表引導連接,那麼您也應該在連接之後對行進行排序。