大量数据如何做分页处理

本文分享自华为云社区《应用中大量数据的分页处理》,作者:码乐。

简介

大批量数据的展示一直被视为一个必须要解决的问题。 一个经典的思想就是分批展示和处理它们。

1 查询时外键的处理

如果在django model 中模型使用了外键,通过on_delete 来定义关联操作。

vbnet 复制代码
CASCADE: 级联操作。如果外键那条数据删除了,这条数据也将被删除
PROTECT: 受保护,只要这条数据引用了外键的那条数据,旧不能删除外键数据,如果强行删除,Django框架将报错
SET_NULL: 设置为空,如果外键数据被删除,本条数据设置为空,前提是 可以设置本条数据为空
SET_DEFAULT: 设置默认值,如果外键数据删除了,设置这个数据的值为默认,前提是有默认值
SET()函数: 如果外键那条数据被删除,那么将会获取SET函数的值作为外键的值。Set()函数可以接受可调用对象,可调用对象的返回值作为结果设置回去。
DO_NOTHING: 不采取任何行为,一切看数据库级别的行为。

数据库层面的约束:

sql 复制代码
	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行丢弃,这样的代价很高。

sql 复制代码
	select * from table order by id limit 10000, 20;

很简单,该语句的意思就是查询10000+20条记录,去掉前10000条,返回后20条。

无疑该查询能够实现分页,但10000这位置的值越大,查询性能就越低,因为MySQL需要扫描全部10000+20条记录。

假设所有的页使用相同的频次访问,这样的查询将平均扫描一半数据表。为了优化他们,你可以在分页视图中限制最多可访问的页数,或者让大批量的查询更有效。

当一个表中有很多符合查询条件的数据的时候,我们往往不需要把他们全部一次性取出来,那样对查询效率或者服务器性能来说都会是一个极大的挑战:例如最简单的商城,假设商城中有一万个数据,但我们在前端可能只会每次看到一页.

sql 复制代码
	select * from table where xxx="xxx" limit 10; 

这表示查询符合条件的10个数据。

sql 复制代码
	select * from table where xxx="xxx" limit 10 offset 10;

这表示分页,查询符合条件的第11到20的数据。

或者通过指定最大id去查询

sql 复制代码
	select * from table where id > #max_id# order by id limit n;

该查询同样会返回后n条记录,却无需像方式1扫描前m条记录,但必须在每次查询时拿到上一次查询(上一页)的最大id(或最小id),是比较常用的方式。

当然该查询的问题也在于,如果最大id不是连续的,则我们不一定能拿到这个id,比如当前在第3页,需要查询第5页的数据,就不行了。

或者通过子查询,先筛选前10000个,找到最大id,然后选择剩余的20个符合要求的

sql 复制代码
	select * from table where id > (select id from table order by id limit m, 1) limit n;

该查询同样是通过子查询扫描字段id, 因为它不需要进行表的关联,而是一个简单的比较,在不知道上一页最大id的情况下,是比较推荐的用法。

左右连接的方式本身性能可能更差。

还有如下子查询、连接表,加索引快速定位元组,然后再读取元组

sql 复制代码
	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

python 复制代码
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)

如果不使用分页,将显示全部的消息在同一个页面

scss 复制代码
        serializer = TaskSerializer(result, many=True)
        return Response(serializer.data)

访问分页数据.默认接口http://127.0.0.1:2001/api/tasks/ 就是分页1

ruby 复制代码
http://127.0.0.1:2001/api/tasks/?page=1  #2,3,4...

2 小结

再重复一次,在有分页查询的应用中,包括 LIMIT 和 OFFSET 的查询十分常见,而且几乎每个都会有一个 ORDER BY 子句。如果使用索引排序的话将对性能优化十分有帮助,否则服务端需要做很多文件排序。

一个高频的问题是 offset 的值过大。如果查询类似 LIMIT 10000, 20,将会产生10020行,并将之前的10000行丢弃,这样的代价很高。

假设所有的页使用相同的频次访问,这样的查询将平均扫描一半数据表。

为了优化他们,你可以在分页视图中限制最多可访问的页数,或者让大量的查询更有效。

点击关注,第一时间了解华为云新鲜技术~

相关推荐
zopple3 小时前
常见的 Spring 项目目录结构
java·后端·spring
cjy0001115 小时前
springboot的 nacos 配置获取不到导致启动失败及日志不输出问题
java·spring boot·后端
小江的记录本5 小时前
【事务】Spring Framework核心——事务管理:ACID特性、隔离级别、传播行为、@Transactional底层原理、失效场景
java·数据库·分布式·后端·sql·spring·面试
sheji34165 小时前
【开题答辩全过程】以 基于springboot的校园失物招领系统为例,包含答辩的问题和答案
java·spring boot·后端
程序员cxuan6 小时前
人麻了,谁把我 ssh 干没了
人工智能·后端·程序员
wuyikeer7 小时前
Spring Framework 中文官方文档
java·后端·spring
Victor3567 小时前
MongoDB(61)如何避免大文档带来的性能问题?
后端
Victor3567 小时前
MongoDB(62)如何避免锁定问题?
后端
wuyikeer8 小时前
Spring BOOT 启动参数
java·spring boot·后端
子木HAPPY阳VIP9 小时前
Ubuntu 22.04 VMware 设置固定IP配置
人工智能·后端·目标检测·机器学习·目标跟踪