mysql查詢語句select-limit使用詳解

1 limit使用簡介
    limit子句是一個選擇語句塊的最後一個子句,它選取了行的一個子集,來限定中間結果的輸出行數。limit子句表示了最前面和最後面被提取的行數。
    通常情況下,Limit關鍵字可以接受一個或者兩個數字參數。需要注意的是,這個參數必須是一個整數常量。如果用戶給定兩個參數,則第一個參數表示第一個返回記錄行的偏移量,第二個參數則表示返回記錄行的最大數據。另外需要提醒的是,初始記錄行的偏移量是0,而不是1。
    雖然使用了Limit語句來限制返回的記錄數,從而可以提高應用程序的工作效率。但是其也會給系統的性能帶來一些負面影響。如可能會導致全表掃描等等。如果數據庫管理員決定使用Limit子句來指定需要顯示的記錄數,那麼最好能夠最大限度的使用索引,以避免全表掃描,提高工作效率。
2 基本語法
SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset
    LIMIT 子句可以被用於強制 SELECT 語句返回指定的記錄數。LIMIT 接受一個或兩個數字參數。參數必須是一個整數常量。如果給定兩個參數,第一個參數指定第一個返回記錄行的偏移量,第二個參數指定返回記錄行的最大數目。初始記錄行的偏移量是 0(而不是 1): 爲了與 PostgreSQL 兼容,MySQL 也支持句法: LIMIT # OFFSET #。

3 創建測試表及數據

    3.1 創建測試表

CREATE   TABLE PLAYERS
        (PLAYERNO       INTEGER      NOT NULL,
         NAME           CHAR(15)     NOT NULL,
         INITIALS       CHAR(3)      NOT NULL,
         BIRTH_DATE     DATE                 ,
         SEX            CHAR(1)      NOT NULL,
         JOINED         SMALLINT     NOT NULL,
         STREET         VARCHAR(30)  NOT NULL,
         HOUSENO        CHAR(4)              ,
         POSTCODE       CHAR(6)              ,
         TOWN           VARCHAR(30)  NOT NULL,
         PHONENO        CHAR(13)             ,
         LEAGUENO       CHAR(4)              ,
         PRIMARY KEY    (PLAYERNO)          );
    注:測試表爲球員信息。

    3.2 插入測試數據

INSERT INTO PLAYERS VALUES (2, 'Everett', 'R', '1948-09-01', 'M', 1975, 'Stoney Road','43', '3575NH', 'Stratford', '070-237893', '2411');
INSERT INTO PLAYERS VALUES (6, 'Parmenter', 'R', '1964-06-25', 'M', 1977, 'Haseltine Lane','80', '1234KK', 'Stratford', '070-476537', '8467');
INSERT INTO PLAYERS VALUES (7, 'Wise', 'GWS', '1963-05-11', 'M', 1981, 'Edgecombe Way','39', '9758VB', 'Stratford', '070-347689', NULL);
INSERT INTO PLAYERS VALUES (8, 'Newcastle', 'B', '1962-07-08', 'F', 1980, 'Station Road','4', '6584WO', 'Inglewood', '070-458458', '2983');
INSERT INTO PLAYERS VALUES (27, 'Collins', 'DD', '1964-12-28', 'F', 1983, 'Long Drive','804', '8457DK', 'Eltham', '079-234857', '2513');
INSERT INTO PLAYERS VALUES (28, 'Collins', 'C', '1963-06-22', 'F', 1983, 'Old Main Road','10', '1294QK', 'Midhurst', '010-659599', NULL);
INSERT INTO PLAYERS VALUES (39, 'Bishop', 'D', '1956-10-29', 'M', 1980, 'Eaton Square','78', '9629CD', 'Stratford', '070-393435', NULL);
INSERT INTO PLAYERS VALUES (44, 'Baker', 'E', '1963-01-09', 'M', 1980, 'Lewis Street','23', '4444LJ', 'Inglewood', '070-368753', '1124');
INSERT INTO PLAYERS VALUES (57, 'Brown', 'M', '1971-08-17', 'M', 1985, 'Edgecombe Way','16', '4377CB', 'Stratford', '070-473458', '6409');
INSERT INTO PLAYERS VALUES (83, 'Hope', 'PK', '1956-11-11', 'M', 1982, 'Magdalene Road','16A', '1812UP', 'Stratford', '070-353548', '1608');
INSERT INTO PLAYERS VALUES (95, 'Miller', 'P', '1963-05-14', 'M', 1972, 'High Street','33A', '5746OP', 'Douglas', '070-867564', NULL);
INSERT INTO PLAYERS VALUES (100, 'Parmenter', 'P', '1963-02-28', 'M', 1979, 'Haseltine Lane','80', '6494SG', 'Stratford', '070-494593', '6524');
INSERT INTO PLAYERS VALUES (104, 'Moorman', 'D', '1970-05-10', 'F', 1984, 'Stout Street','65', '9437AO', 'Eltham', '079-987571', '7060');
INSERT INTO PLAYERS VALUES (112, 'Bailey', 'IP', '1963-10-01', 'F', 1984, 'Vixen Road','8', '6392LK', 'Plymouth', '010-548745', '1319');

4 limit簡單實例

    4.1 實例1

    獲取前四個最大球員的號碼和名字。

select playerno, name 
from players
order by playerno desc
limit 4;

    4.2 實例2

    獲取加入球隊最早的2個球員的號碼和名字。

select playerno, name 
from players 
order by joined desc 
limit 2;

    注:112號球員和104號球員都是1984年加入足球俱樂部的,因爲最終輸出爲兩個球員,57號球員是1985年加入的,肯定會輸出,對於年份重複的112和104號球員mysql會隨機選取一個。
    4.3 實例3

    獲取加入球隊最早的2個球員的號碼和名字,如果有年份重複的,只顯示球員號最小的球員。

select playerno, name 
from players 
order by joined desc, playerno asc
limit 2;

    注:如果不指定重複年份加入俱樂部隊員的選取規則的話,mysql會按照默認規則選取,指定的話如playerno asc,則按球員號從小到大選取。

5 limit與子查詢

    limit也可用在出現在子查詢中的語句塊塊兒中。

select * from 
(select playerno, name 
from players 
order by joined desc, playerno asc
limit 2) as T
order by playerno desc;

6 limit偏移量

    通常limit子句用來選擇列表頭部或尾部,添加一個偏移量則可跳過幾行。添加偏移量有兩種方式,分別是LIMIT [offset,] rows 或LIMIT rows OFFSET offset,推薦使用第二種,它更明確地表示了要顯示的行數和偏移的行數。

select playerno, name 
from players
order by playerno asc
limit 3, 4;
    或者

select playerno, name 
from players
order by playerno asc
limit 4 offset 3;

7 limit 可選選項sql_calc_found_rows

    我們可以通過limit指定我們需要輸出的行,加上選項sql_calc_found_rows的話,可以在後臺統計出來總的行數,如我們只需要顯示4行,並統計下總的行數,可通過select  found_rows()獲得。

mysql> select sql_calc_found_rows playerno, name 
    -> from players
    -> order by playerno desc
    -> limit 4;
+----------+-----------+
| playerno | name      |
+----------+-----------+
|      112 | Bailey    |
|      104 | Moorman   |
|      100 | Parmenter |
|       95 | Miller    |
+----------+-----------+
mysql> select found_rows();
+--------------+
| found_rows() |
+--------------+
|           14 |
+--------------+

8 limit優化

    8.1 limit 0子句

    根據Limit關鍵字的定義,如果參數爲0的話,則其返回的是空記錄。在實際工作中,靈活使用這個0參數,能夠給我們帶來很大的收穫。
    如現在數據庫工程師想要確認一下某個查詢語句的有效性,如果直接運行這個查詢語句,需要等待其返回的記錄。如果涉及的紀錄數量比較多,或者運算邏輯比較複雜,那麼需要等到比較長的時間。此時就可以在Select查詢語句中,使用Limit 0子句。只要查詢語句沒有語法上的錯誤,這就可以讓數據庫快速的返回一個空集合。從而幫助數據庫設計人員迅速的判斷查詢語句的有效性。另外這個空集和中還會返回某個表的各個字段的字段名稱。即通過這個Limit 0子句還可以查詢某個表的表結構。


    可見靈活應用limit 0子句,確實能夠給我們帶來不小的收益。不過需要注意的是,在某些特定的場合下,這個子句可能不會奏效。如通常情況下,在Monitor工作環境中不支持這個Limit 0子句。此時結果只會顯示Empty Set,而不是我們所需要的結果。


    8.2 limit與distinct

    Distinct關鍵字主要用來過濾重複的記錄。而Limit關鍵字則主要用來指定記錄所返回的行數。如果這兩個關鍵字共同使用時,如Limit的參數爲50,則數據庫返回50條不重複的記錄數。然後後續的查詢就會停止。如果查詢的記錄中有重複記錄,則數據庫查詢的實際數量往往要比Limit關鍵字所指定的數量要多。

mysql> select joined from players;         
+--------+
| joined |
+--------+
|   1975 |
|   1977 |
|   1981 |
|   1980 |
|   1983 |
|   1983 |
|   1980 |
|   1980 |
|   1985 |
|   1982 |
|   1972 |
|   1979 |
|   1984 |
|   1984 |
+--------+
    注:全部查詢行數爲14
mysql> select joined from players limit 6;         
+--------+
| joined |
+--------+
|   1975 |
|   1977 |
|   1981 |
|   1980 |
|   1983 |
|   1983 |
+--------+
    注:查詢行數爲6
mysql> select distinct joined from players limit 6;
+--------+
| joined |
+--------+
|   1975 |
|   1977 |
|   1981 |
|   1980 |
|   1983 |
|   1985 |
+--------+
    注:查詢行數爲9
    8.3 limit分頁查詢優化

    MySQL的limit給分頁帶來了極大的方便,但數據量一大的時候,limit的性能就急劇下降。

    8.3.1 offset比較小的時候,直接使用limit。

select name 
from players 
order by playerno 
limit 5, 6; 

    

    8.3.2 offset比較大的時候,使用子查詢優化。

select name 
from players 
where playerno >= 
    (select playerno 
     from players 
     order by playerno 
     limit 5, 1)
limit 6; 
    

    注:首先獲取到offset的id然後直接使用limit size來獲取數據。
    8.4 limit與索引

    如果數據庫管理員決定使用Limit子句來指定需要顯示的記錄數,那麼最好能夠最大限度的使用索引,以避免全表掃描,提高工作效率。即當數據庫選擇做完整的表掃描時,可以在某些情況下使用索引。
    如現在數據庫管理員決定將Limit子句與Order BY子句一起使用。數據庫一旦找到了排序結果的第一個RowCount行,則系統將會結束排序,而並不會對整個表進行排序。如果單獨使用Order By子句的話,則會對整個表進行排序。雖然如此,但是排序必定要浪費一定的時間。此時數據庫管理員如果決定使用索引,則可以在很大程度上提高這個查詢的效率。

    8.5 limit與group by

    Group By關鍵字主要用來對數據進行分類彙總。不過在分類彙總之前,往往需要對數據先進性排序。而Limit語句用來指定顯示的結果數量時,往往也需要涉及到紀錄的分類彙總與排序的問題。如現在一個學校成績管理系統中,需要對學生的總分進行排序。即先對學生各科成績進行彙總,然後顯示其排名爲前50的紀錄。此時就需要同時用到Group By子句和Limit子句。其實從這個案例中我們也可以看出,這兩個子句相互依賴的特性。正是因爲這種特性(經常相互結合使用),爲此結合Group By子句可以提高Limit的查詢效率。
    這主要是因爲兩者如果一起使用的話,Limit關鍵字將不會再重複計算任何不必要的Group By的值。換句話說,在某些情況下,Group By子句能夠通過順序來讀取鍵或者在鍵上做排序來解決分類彙總時的排序問題,然後再計算摘要直到關鍵字的值的改變爲止。如此的話,兩個子句所需要做的一些共同性的工作,只要做一次即可。這就可以從另外一次角度用來提高應用系統的性能。相比先做一個視圖對數據進行分類彙總的運算,再使用一個查詢語句來抽取特定數量的記錄,效率就要高一點。因爲後者是將兩個子句分開來使用,就無法享受到結合使用所體現的優勢。


****************************************************************************************
    原文地址:http://blog.csdn.net/jesseyoung/article/details/40298241
    博客主頁:http://blog.csdn.net/jesseyoung
****************************************************************************************

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章