1. 程式人生 > >MySQL5.6中limit的工作機制和order by limit優化原理

MySQL5.6中limit的工作機制和order by limit優化原理

MySQL5.6中Limit的工作機制

如果你僅需要在一個結果集中返回特定的幾行,通常是使用limit,而不是取回整個結果集再捨去不需要的資料,MySQL通常按照如下的方式優化一個包含limit row_count或HAVING的語句:

◎只有limit

如果你只通過limit返回少量的行,那麼正常情況下mysql會使用全盤掃描,有些場合會使用索引,以下是使用了覆蓋索引的情況:


以下是使用全表掃描的情況:


◎order by和limit

如果你order by和limit一起使用,那麼mysql在排序結果中找到最初的row_count行之後就會完成這條語句,而不是對整個結果集進行排序。如果使用了索引排序,它就非常快地完成。如果整個filesort必須都做完的話,那麼在找到最初的row_count行之前,匹配該查詢的所有行都將被select,並且做sort操作。如果這些行找到了,mysql將不會對剩餘的結果集進行排序。

◎distinct和limit

當limit row_count和distinct一起使用時,MySQL在找到最初的unique的row_count行之後就會停止檢索。

◎group by和limit

在某些場合下,group by會用於某些key行的排序,並且計算彙總資訊,這時如果使用limit row_count的話將不會計算任何額外的grup by值。

◎SQL_CALC_FOUND_ROWS和limit

只要MySQL已經返回了需要的行數給客戶端,它將終止這個查詢,除非你在查詢中使用了SQL_CALC_FOUND_ROWS。

◎limit 0的用法

Limit 0會非常快地返回一個空結果,這個功能可被應用於檢測一條SQL的合法性。

◎臨時表和limit

如果伺服器在查詢中使用了臨時表,它會使用limit row_count語句來計算需求的空間大小。

Order by和Limit混合使用引起的問題

如果在order by語句中返回的結果集有很多行,那麼非排序的列的返回結果是不確定的,即隨機的,所以如果配合limit的話每次返回的結果集的順序是不固定的,比如下面這個例子

mysql> SELECT * FROM ratings ORDER BY category;

+----+----------+--------+

| id | category | rating |

+----+----------+--------+

|  1 |        1 |   4.5 |

|  5 |        1 |   3.2 |

|  3 |        2 |   3.7 |

|  4 |        2 |   3.5 |

|  6 |        2 |   3.5 |

|  2 |        3 |   5.0 |

|  7 |        3 |   2.7 |

+----+----------+--------+

使用了limit以後,可發現id列和rating列和之前的結果集順序有出入:

mysql> SELECT * FROM ratings ORDER BY category LIMIT 5;

+----+----------+--------+

| id | category | rating |

+----+----------+--------+

|  1 |        1 |   4.5 |

|  5 |        1 |   3.2 |

|  4 |        2 |   3.5 |

|  3 |        2 |   3.7 |

|  6 |        2 |   3.5 |

+----+----------+--------+

如果你有必要保證每次有相同的結果集,則需要order by你需要的那幾列了:

mysql> SELECT * FROM ratings ORDER BY category, id;

+----+----------+--------+

| id | category | rating |

+----+----------+--------+

|  1 |        1 |   4.5 |

|  5 |        1 |   3.2 |

|  3 |        2 |   3.7 |

|  4 |        2 |   3.5 |

|  6 |        2 |   3.5 |

|  2 |        3 |   5.0 |

|  7 |        3 |   2.7 |

+----+----------+--------+

mysql> SELECT * FROM ratings ORDER BY category, id LIMIT 5;

+----+----------+--------+

| id | category | rating |

+----+----------+--------+

|  1 |        1 |   4.5 |

|  5 |        1 |   3.2 |

|  3 |        2 |   3.7 |

|  4 |        2 |   3.5 |

|  6 |        2 |   3.5 |

+----+----------+--------+

Order by和limit一起使用的優化原理

從MySQL5.6.2版本以後,優化器將更加智慧地處理下面形式的查詢了

SELECT ... FROM single_table ... ORDER BY non_index_column [DESC] LIMIT [M,]N;

這種在很大的結果集中只返回很少的行數的查詢型別在web應用中非常常見,比如

SELECT col1, ... FROM t1 ... ORDER BY name LIMIT 10;

SELECT col1, ... FROM t1 ... ORDER BY RAND() LIMIT 15;

排序快取有一個引數是sort_buffer_size,如果這個引數大小足夠上面範例中的N行的排序結果集(如果M也被定義,那就是M+N行的結果集大小),那麼伺服器將會避免一個檔案排序操作,使得排序完全在記憶體中完成。

記憶體排序+limit原理

1 掃描表,在記憶體中插入那些被選擇排序的列的資料到一個排好序的佇列中,比如order by col1,col2,則插入col1和col2列的資料。如果佇列滿了,則擠出排序在末尾的資料。

2 返回佇列中的前N行記錄,如果M也被定義,則調到第M行開始返回後續的N行記錄。

檔案排序+limit原理

1掃描表,重複步驟2和3,直到表的結尾

2選中這些行數直到排序快取被填滿

3在排序快取中寫入第一個N行(如果M被定義,則M+N行)到一個排序檔案中。

兩者比較

在記憶體中排序和使用檔案排序相比,掃描表的代價幾乎是一樣的,不同的是其他的開銷:

記憶體排序的方法在插入資料到一個有序佇列中會牽扯到更多的cpu資源,而檔案排序會消耗更多的磁碟IO,優化器在考慮兩者的平衡性上會主要考慮N的值大小