大量數據如何做分頁處理

本文分享自華爲雲社區《應用中大量數據的分頁處理》,作者:碼樂。

簡介

大批量數據的展示一直被視爲一個必須要解決的問題。 一個經典的思想就是分批展示和處理它們。

1 查詢時外鍵的處理

如果在django model 中模型使用了外鍵,通過on_delete 來定義關聯操作。

CASCADE: 級聯操作。如果外鍵那條數據刪除了,這條數據也將被刪除
PROTECT: 受保護,只要這條數據引用了外鍵的那條數據,舊不能刪除外鍵數據,如果強行刪除,Django框架將報錯
SET_NULL: 設置爲空,如果外鍵數據被刪除,本條數據設置爲空,前提是 可以設置本條數據爲空
SET_DEFAULT: 設置默認值,如果外鍵數據刪除了,設置這個數據的值爲默認,前提是有默認值
SET()函數: 如果外鍵那條數據被刪除,那麼將會獲取SET函數的值作爲外鍵的值。Set()函數可以接受可調用對象,可調用對象的返回值作爲結果設置回去。
DO_NOTHING: 不採取任何行爲,一切看數據庫級別的行爲。

數據庫層面的約束:

PESTRICT: 默認選項,如果要刪除父表記錄,如果子表有關聯記錄,則不允許刪除
	NOACTION:同上,首先檢測外鍵
	CASCADE: 父表delete,update時,子表關聯操作 也進行 delete,update
	SET NULL:父表delete , update時,子表將關聯記錄外鍵字段設置爲null,所以設計子表時不能 not null

這些外鍵的方法工具,可以幫助使用者處理多表關聯查詢任務。

1.1 如何在django中查詢分頁

在有分頁查詢的應用中,包括 LIMIT 和 OFFSET 的查詢十分常見,而且幾乎每個都會有一個 ORDER BY 子句。

如果使用索引排序的話將對性能優化十分有幫助,否則服務端需要做很多文件排序。

一個高頻的問題是 offset 的值過大。如果查詢類似 LIMIT 10000, 20,將會產生10020行,並將之前的10000行丟棄,這樣的代價很高。

select * from table order by id limit 10000, 20;

很簡單,該語句的意思就是查詢10000+20條記錄,去掉前10000條,返回後20條。
無疑該查詢能夠實現分頁,但10000這位置的值越大,查詢性能就越低,因爲MySQL需要掃描全部10000+20條記錄。

假設所有的頁使用相同的頻次訪問,這樣的查詢將平均掃描一半數據表。爲了優化他們,你可以在分頁視圖中限制最多可訪問的頁數,或者讓大批量的查詢更有效。

當一個表中有很多符合查詢條件的數據的時候,我們往往不需要把他們全部一次性取出來,那樣對查詢效率或者服務器性能來說都會是一個極大的挑戰:例如最簡單的商城,假設商城中有一萬個數據,但我們在前端可能只會每次看到一頁.

select * from table where xxx="xxx" limit 10;

這表示查詢符合條件的10個數據。

select * from table where xxx="xxx" limit 10 offset 10;

這表示分頁,查詢符合條件的第11到20的數據。

或者通過指定最大id去查詢

select * from table where id > #max_id# order by id limit n;

該查詢同樣會返回後n條記錄,卻無需像方式1掃描前m條記錄,但必須在每次查詢時拿到上一次查詢(上一頁)的最大id(或最小id),是比較常用的方式。

當然該查詢的問題也在於,如果最大id不是連續的,則我們不一定能拿到這個id,比如當前在第3頁,需要查詢第5頁的數據,就不行了。

或者通過子查詢,先篩選前10000個,找到最大id,然後選擇剩餘的20個符合要求的

select * from table where id > (select id from table order by id limit m, 1) limit n;

該查詢同樣是通過子查詢掃描字段id, 因爲它不需要進行表的關聯,而是一個簡單的比較,在不知道上一頁最大id的情況下,是比較推薦的用法。

左右連接的方式本身性能可能更差。
還有如下子查詢、連接表,加索引快速定位元組,然後再讀取元組

SELECT * FROM table WHERE id <= (SELECT id FROM table ORDER BY id DESC LIMIT (page-1)*pagesize ORDER BY id DESC LIMIT pagesize)

rest_framework 內建了分頁的操作模塊,讓我們來應用到具體函數即可 employee/views.py

from rest_framework.pagination import PageNumberPagination
@api_view(['GET', 'POST']) 
@permission_classes([CustomPermission])
def blog_api_view(request):
    """"""
    if request.method == "GET":
		paginator = PageNumberPagination()
        # paginator.page_size = 1 setting we display only 1 item per page.
        paginator.page_size = 2
        task_objects = EmployeeSign.objects.all()
        result = paginator.paginate_queryset(task_objects, request)

如果不使用分頁,將顯示全部的消息在同一個頁面

serializer = TaskSerializer(result, many=True)
        return Response(serializer.data)

訪問分頁數據.默認接口http://127.0.0.1:2001/api/tasks/ 就是分頁1

http://127.0.0.1:2001/api/tasks/?page=1  #2,3,4...

2 小結

再重複一次,在有分頁查詢的應用中,包括 LIMIT 和 OFFSET 的查詢十分常見,而且幾乎每個都會有一個 ORDER BY 子句。如果使用索引排序的話將對性能優化十分有幫助,否則服務端需要做很多文件排序。

一個高頻的問題是 offset 的值過大。如果查詢類似 LIMIT 10000, 20,將會產生10020行,並將之前的10000行丟棄,這樣的代價很高。

假設所有的頁使用相同的頻次訪問,這樣的查詢將平均掃描一半數據表。

爲了優化他們,你可以在分頁視圖中限制最多可訪問的頁數,或者讓大量的查詢更有效。

點擊關注,第一時間瞭解華爲雲新鮮技術~

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