MySQL 分頁是 Web 開發中非常核心的技術,用于在大量數據中高效地顯示指定頁的內容。其核心實現方式是使用 LIMIT 和 OFFSET 子句。
MySQL 中實現分頁主要依靠 LIMIT 關鍵字,它有兩種用法: 1. LIMIT count : 只返回前 count 條記錄。 2. LIMIT offset, count : 從第 offset 條記錄開始,返回 count 條記錄。 等價于 LIMIT count OFFSET offset (這是更符合標準SQL的寫法,推薦使用)。
要獲取第 page_num 頁(頁碼從 1 開始),每頁大小為 page_size 的數據,其計算公式為:
SELECT * FROM table_name [WHERE ...] [ORDER BY ...] -- 分頁必須有確定的排序,否則順序混亂! LIMIT (page_num - 1) * page_size, page_size; -- 或使用標準寫法: SELECT * FROM table_name [WHERE ...] [ORDER BY ...] LIMIT page_size OFFSET (page_num - 1) * page_size;
假設我們有一個 articles 表,要按發布時間倒序進行分頁。
SELECT id, title, created_time FROM articles ORDER BY created_time DESC -- 必須排序! LIMIT 0, 10; -- 或 SELECT id, title, created_time FROM articles ORDER BY created_time DESC LIMIT 10 OFFSET 0;
-- 偏移量 offset = (3 - 1) * 10 = 20 SELECT id, title, created_time FROM articles ORDER BY created_time DESC LIMIT 20, 10; -- 或(標準寫法) SELECT id, title, created_time FROM articles ORDER BY created_time DESC LIMIT 10 OFFSET 20;
在 Web 后端(如 Flask, Django)中,你通常會從前端接收 page (當前頁)和 size (每頁大。﹨。
import pymysql def get_articles(page=1, size=10): """ 分頁獲取文章列表 :param page: 頁碼,從1開始 :param size: 每頁大小 :return: 文章列表 """ offset = (page - 1) * size計算偏移量 connection = pymysql.connect(host='localhost', user='user', password='pass', database='db') try: with connection.cursor(pymysql.cursors.DictCursor) as cursor: 1. 查詢分頁數據 sql = """ SELECT id, title, created_time FROM articles ORDER BY created_time DESC LIMIT %s OFFSET %s """ cursor.execute(sql, (size, offset)) data = cursor.fetchall() 2. (重要)查詢總記錄數,用于計算總頁數 count_sql = "SELECT COUNT(*) AS total FROM articles" cursor.execute(count_sql) total_count = cursor.fetchone()['total'] total_pages = (total_count + size - 1) // size向上取整計算總頁數 return { 'data': data, 'pagination': { 'current_page': page, 'page_size': size, 'total_count': total_count, 'total_pages': total_pages, 'has_next': page < total_pages, 'has_prev': page > 1 } } finally: connection.close() 調用示例:獲取第二頁,每頁5條 result = get_articles(page=2, size=5) print(result['data']) print(f"總共有 {result['pagination']['total_pages']} 頁")
問題: 當偏移量 OFFSET 非常大時(如 LIMIT 1000000, 20 ),MySQL 需要先掃描并跳過前 1000000 條記錄,這會導致性能急劇下降。
使用“游標分頁”或“鍵集分頁” 這種方法不依賴于 OFFSET ,而是記住上一頁最后一條記錄的位置,然后查詢“之后”的記錄。它適用于無限滾動或下一頁的場景。
前提: 排序字段必須具有唯一性(通常是一個自增ID或時間戳)。
-- 傳統分頁(慢): SELECT * FROM table ORDER BY id DESC LIMIT 1000000, 20; -- 鍵集分頁(快): -- 假設我們已知上一頁最后一條記錄的 id 是 1020 SELECT * FROM table WHERE id < 1020 -- 基于已知的最后一個ID進行查詢 ORDER BY id DESC LIMIT 20;
優點: 速度極快,性能不受頁碼影響。 缺點: 無法直接跳到任意頁碼,只能“上一頁”或“下一頁”。
使用覆蓋索引優化 讓查詢所需的字段都包含在索引中,這樣數據庫可以直接在索引中完成操作,避免回表。
-- 假設在 (created_time, id, title) 上有一個復合索引 -- 不好的查詢:SELECT * FROM articles ... (需要回表獲取所有字段) -- 好的查詢:SELECT id, title, created_time FROM articles ... (所需字段全在索引里)
1.一定要排序:使用 ORDER BY 確保分頁順序是確定的。 2.性能優先:對于深度分頁(如第1000頁以后),強烈推薦使用鍵集分頁。 3.避免 SELECT * :只查詢需要的字段,結合覆蓋索引可以極大提升性能。 4.參數化查詢:在應用程序中,一定要使用參數化查詢來拼接 LIMIT 和 OFFSET ,防止SQL注入。
最終建議: 對于后臺管理系統等需要跳頁的場景,如果數據量不是特別大,使用傳統的 LIMIT OFFSET 。 對于C端產品(如App、新聞站)、數據量巨大的表,優先采用鍵集分頁來實現“無限滾動”。
另外搭配便捷的MYSQL備份工具,可定時備份、異地備份,MYSQL導出導入?杀镜剡B接LINUX里的MYSQL,簡單便捷?梢源蟠蟮靥岣吖ぷ餍枢浮