天天看點

mysql實作翻頁功能1.limit分頁公式2. 分頁方式3. 優化

1.limit分頁公式

1.1 limit分頁公式

1.limit分頁公式:curPage是目前第幾頁

上一頁:limit (curPage-1)*pageSize,pageSize

下一頁:limit (curPage+1)*pageSize,pageSize

2.sql

select * from student order by sid limit (curPage-1)*pageSize,pageSize
           

1.2 擷取總頁碼

1.總頁數公式:totalRecord是總記錄數;pageSize是一頁分多少條記錄

int totalPageNum = (totalRecord +pageSize - 1) / pageSize;

2.用途:前台UI分頁插件顯示分頁碼

3.詢總條數:totalRecord是總記錄數: SELECT COUNT(*) FROM student

2. 分頁方式

2.1 limit m,n分頁

limit 3,3的意思掃描滿足條件的3+3行,撇去前面的3行,傳回最後的3行,那麼問題來了,如果是limit 200000,200,需要掃描200200行,如果在一個高并發的應用裡,每次查詢需要掃描超過20W行,效率十分低下。

import pymysql

conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='test')
  
# 遊标設定為字典類型
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)

def view_page():
    current_page_no = 0
    init_status = None
    while True:
        result = []
        status = input("請翻頁(1:上一頁,2:下一頁):")
        if int(status)==1:
            if current_page_no>0:
                print(f"目前頁是第{current_page_no}頁, 您選擇了上一頁")
            else:
                page = current_page_no+1
                print(f"目前頁是第{page}頁, 您選擇了上一頁")
            if init_status==None:
                pass
            elif not init_status:
                current_page_no = current_page_no -1;
            else:
                pass
            if current_page_no - 1>0:
                current_page_no = current_page_no - 1
                cursor.execute("select * from student order by sid limit %s,10", (current_page_no*10))
                result = cursor.fetchall()
            else:
                current_page_no = 0
                cursor.execute("select * from student order by sid limit %s,10",(current_page_no))
                result = cursor.fetchall()
            init_status = True
        elif int(status)==2:
            if current_page_no>0:
                print(f"目前頁是第{current_page_no}頁, 您選擇了下一頁")
            else:
                page = current_page_no+1
                print(f"目前頁是第{page}頁, 您選擇了下一頁")
            
            if init_status==None:
                pass
            elif init_status:
                current_page_no = current_page_no + 1
            else:
                pass
            cursor.execute("select * from student order by sid limit %s,10", (current_page_no*10))
            result = cursor.fetchall()
            current_page_no = current_page_no + 1;
            init_status = False
        else:
            print("請輸入正确的代碼。")
        for info in result:
            print(info)
view_page()
           

2.2 limit m

//下一頁
select * from student where sid >10 order by sid asc limit 10
//上一頁
select * from student where sid <60 order by sid desc limit 10
           

這種方式不管翻多少頁隻需要掃描n條資料。

但是,雖然掃描的資料量少了,但是在某些需要跳轉到多少也得時候就無法實作,這時還是需要用到方法1,既然不能避免,那麼我們可以考慮盡量減小m的值,是以我們可以給這條語句加上一個條件限制。使得每次掃描不用從第一條開始。這樣就能盡量減少掃描的資料量。

2.3

例如:每頁10條資料,目前是第10頁,目前條目ID的最大值是109,最小值是100.(目前100-109)

跳到第9頁:

跳到第8頁:

跳到第6頁:

跳到第11頁:

3. 優化

3.1 使用子查詢優化

這種方式先定位偏移位置的 id,然後往後查詢,這種方式适用于 id 遞增的情況。

//0.0037
select * from student where sname="了解" limit 5000,1

//0.0025
select sid from student where sname="了解" limit 5000,1

//0.0021
SELECT
    *
FROM
    student
WHERE
    sname = "了解" AND sid >=(
    SELECT
        sid
    FROM
        student
    WHERE
        sname = "了解"
    LIMIT 5000,
    1
)
LIMIT 100;

//0.0030
select * from student where sname="了解" limit 5000,100
           

1>比較第1條語句和第2條語句:使用 select id 代替 select * 速度增加了3倍

2>比較第2條語句和第3條語句:速度相差幾十毫秒

3>比較第3條語句和第4條語句:得益于 select id 速度增加,第3條語句查詢速度增加了3倍

3.2 使用 id 限定優化

這種方式假設資料表的id是連續遞增的,則我們根據查詢的頁數和查詢的記錄數可以算出查詢的id的範圍,可以使用 id between and 來查詢:’

select * from student where sname="了解"
and sid between 1000000 and 1000100 limit 100;
           

這種查詢方式能夠極大地優化查詢速度,基本能夠在幾十毫秒之内完成。限制是隻能使用于明确知道id的情況,不過一般建立表的時候,都會添加基本的id字段,這為分頁查詢帶來很多便利。

還可以有另外一種寫法:

當然還可以使用 in 的方式來進行查詢,這種方式經常用在多表關聯的時候進行查詢,使用其他表查詢的id集合,來進行查詢:

select * from student where id in
(select student_id from class where class_id=1)
limit 100;
           

3.3 使用臨時表優化

這種方式已經不屬于查詢優化,這兒附帶提一下。

對于使用 id 限定優化中的問題,需要 id 是連續遞增的,但是在一些場景下,比如使用曆史表的時候,或者出現過資料缺失問題時,可以考慮使用臨時存儲的表來記錄分頁的id,使用分頁的id來進行 in 查詢。這樣能夠極大的提高傳統的分頁查詢速度,尤其是資料量上千萬的時候。

3.4 關于資料表的id說明

一般情況下,在資料庫中建立表的時候,強制為每一張表添加 id 遞增字段,這樣友善查詢。

如果像是訂單庫等資料量非常龐大,一般會進行分庫分表。這個時候不建議使用資料庫的 id 作為唯一辨別,而應該使用分布式的高并發唯一 id 生成器來生成,并在資料表中使用另外的字段來存儲這個唯一辨別。

使用先使用範圍查詢定位 id (或者索引),然後再使用索引進行定位資料,能夠提高好幾倍查詢速度。即先 select id,然後再 select *;

https://blog.csdn.net/bandaoyu/article/details/89844673