java中的分页 效率考虑_面试官:数据量很大,分页查询很慢,有什么优化方案?...
当需要从数据库查询的表有上万条记录的时候,一次性查询所有结果会变得很慢,特别是随着数据量的增加特别明显,这时需要使用分页查询。对于数据库分页查询,也有很多种方法和优化的点。
下面简单说一下我知道的一些方法。
准备工作
为了对下面列举的一些优化进行测试,下面针对已有的一张表进行说明。
表名:order_history
描述:某个业务的订单历史表
主要字段:unsigned int id,tinyint(4) int type
字段情况:该表一共37个字段,不包含text等大型数据,最大为varchar(500),id字段为索引,且为递增。
数据量:5709294
MySQL版本:5.7.16 线下找一张百万级的测试表可不容易,如果需要自己测试的话,可以写shell脚本什么的插入数据进行测试。 以下的 sql 所有语句执行的环境没有发生改变,下面是基本测试结果:
select count(*) from orders_history;
返回结果:5709294
三次查询时间分别为:
8903 ms
8323 ms
8401 ms
一般分页查询
一般的分页查询使用简单的 limit 子句就可以实现。limit 子句声明如下:
SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset
LIMIT 子句可以被用于指定 SELECT 语句返回的记录数。需注意以下几点:
第一个参数指定第一个返回记录行的偏移量,注意从 0开始
第二个参数指定返回记录行的最大数目
如果只给定一个参数:它表示返回最大的记录行数目
第二个参数为 -1 表示检索从某一个偏移量到记录集的结束所有的记录行
初始记录行的偏移量是 0(而不是 1)
下面是一个应用实例:
select * from orders_history where type=8 limit 1000,10;
该条语句将会从表 orders_history 中查询 offset:1000开始之后的10条数据,也就是第1001条到第1010条数据( 1001<=id<=1010)。
数据表中的记录默认使用主键(一般为id)排序,上面的结果相当于:
select * from orders_history where type=8 order by id limit 10000,10;
三次查询时间分别为:
3040 ms
3063 ms
3018 ms
针对这种查询方式,下面测试查询记录量对时间的影响:
select * from orders_history where type=8 limit 10000,1;
select * from orders_history where type=8 limit 10000,10;
select * from orders_history where type=8 limit 10000,100;
select * from orders_history where type=8 limit 10000,1000;
select * from orders_history where type=8 limit 10000,10000;
三次查询时间如下:
查询1条记录:3072ms 3092ms 3002ms
查询10条记录:3081ms 3077ms 3032ms
查询100条记录:3118ms 3200ms 3128ms
查询1000条记录:3412ms 3468ms 3394ms
查询10000条记录:3749ms 3802ms 3696ms
另外我还做了十来次查询,从查询时间来看,基本可以确定,在查询记录量低于100时,查询时间基本没有差距,随着查询记录量越来越大,所花费的时间也会越来越多。
针对查询偏移量的测试:
select * from orders_history where type=8 limit 100,100;
select * from orders_history where type=8 limit 1000,100;
select * from orders_history where type=8 limit 10000,100;
select * from orders_history where type=8 limit 100000,100;
select * from orders_history where type=8 limit 1000000,100;
三次查询时间如下:
查询100偏移:25ms 24ms 24ms
查询1000偏移:78ms 76ms 77ms
查询10000偏移:3092ms 3212ms 3128ms
查询100000偏移:3878ms 3812ms 3798ms
查询1000000偏移:14608ms 14062ms 14700ms
随着查询偏移的增大,尤其查询偏移大于10万以后,查询时间急剧增加。
这种分页查询方式会从数据库第一条记录开始扫描,所以越往后,查询速度越慢,而且查询的数据越多,也会拖慢总查询速度。
使用子查询优化
这种方式先定位偏移位置的 id,然后往后查询,这种方式适用于 id 递增的情况。
select * from orders_history where type=8 limit 100000,1;
select id from orders_history where type=8 limit 100000,1;
select * from orders_history where type=8 and` id>=(select id from orders_history where type=8 limit 100000,1) `limit 100;
select * from orders_history where type=8 limit 100000,100;
4条语句的查询时间如下:
第1条语句:3674ms
第2条语句:1315ms
第3条语句:1327ms
第4条语句:3710ms
针对上面的查询需要注意:
比较第1条语句和第2条语句:使用 select id 代替 select * 速度增加了3倍
比较第2条语句和第3条语句:速度相差几十毫秒
比较第3条语句和第4条语句:得益于 select id 速度增加,第3条语句查询速度增加了3倍
这种方式相较于原始一般的查询方法,将会增快数倍。
使用 id 限定优化
这种方式假设数据表的id是连续递增的,则我们根据查询的页数和查询的记录数可以算出查询的id的范围,可以使用 id between and 来查询:
select * from orders_history where type=2
and id between 1000000 and 1000100 limit 100;`
查询时间:15ms 12ms 9ms
这种查询方式能够极大地优化查询速度,基本能够在几十毫秒之内完成。限制是只能使用于明确知道id的情况,不过一般建立表的时候,都会添加基本的id字段,这为分页查询带来很多便利。
还可以有另外一种写法:
select * from orders_history where id >= 1000001 limit 100;
当然还可以使用 in 的方式来进行查询,这种方式经常用在多表关联的时候进行查询,使用其他表查询的id集合,来进行查询:
select * from orders_history where id in
(select order_id from trade_2 where goods = 'pen')
limit 100;
这种 in 查询的方式要注意:某些 mysql 版本不支持在 in 子句中使用 limit。
使用临时表优化
这种方式已经不属于查询优化,这儿附带提一下。
对于使用 id 限定优化中的问题,需要 id 是连续递增的,但是在一些场景下,比如使用历史表的时候,或者出现过数据缺失问题时,可以考虑使用临时存储的表来记录分页的id,使用分页的id来进行 in 查询。这样能够极大的提高传统的分页查询速度,尤其是数据量上千万的时候。
关于数据表的id说明
一般情况下,在数据库中建立表的时候,强制为每一张表添加 id 递增字段,这样方便查询。
如果像是订单库等数据量非常庞大,一般会进行分库分表。这个时候不建议使用数据库的 id 作为唯一标识,而应该使用分布式的高并发唯一 id 生成器来生成,并在数据表中使用另外的字段来存储这个唯一标识。
使用先使用范围查询定位 id (或者索引),然后再使用索引进行定位数据,能够提高好几倍查询速度。即先 select id,然后再 select *;
相关文章:

dede 后台 mysql_织梦dedecms使用Mysql8.0无法登录后台的解决办法
1//只允许用户名和密码用0-9,a-z,A-Z,,_,.,-这些字符2$this->userName preg_replace("/[^0-9a-zA-Z_!\.-]/", , $username);3$this->userPwd preg_replace("/[^0-9a-zA-Z_!\.-]/", , $userpwd);4$pwd substr(md5($this->userPwd), 5, 20);56$d…

怎样对拍、如何对拍、对拍模板
我写了一个对拍模板,套上直接可以用,还有使用说明在里面,这里附上github网站。 对拍全套模板 转载于:https://www.cnblogs.com/yichuan-sun/p/9624162.html

二叉树线索化示意图_103-线索化二叉树思路图解
2.网上数据结构和算法的课程不少,但存在两个问题:1)授课方式单一,大多是照着代码念一遍,数据结构和算法本身就比较难理解,对基础好的学员来说,还好一点,对基础不好的学生来说,基本上…

linux环境下搭建osm_web服务器一(Postgresql配置及osm2pgsql原始数据导入):
Postgresql配置及osm2pgsql原始数据导入 2012年,Ubuntu 12.04LTS发布,又一个长效支持版,我们又该更新OpenStreetMap服务器了,这次,将详细在博客中记录配置过程。关于前面对OpenStreetMap的介绍,参考我的博文…

Java开发买低压本还是标压本_标压和低压,笔记本怎么选才最香?
华为最近发布了新款 MateBook 13/14 2020 锐龙版笔记本电脑,与之前的产品相比,它们都采用了 AMD 锐龙标压处理器。在体验这两款产品的同时,我一直在思考两个问题:它们与低压处理器相比强在哪里,以及是否值得购买。按照…

php mysql 备注_php,mysql备注信息1
/*---------------------------------------------------------------------------------------如何彻底地删除表?如果你不需要一个表了,你可以使用DROP.语法如下:DROP TABLE tablename例如:DROP TABLE employee_dataQuery OK,0 rows affected(0.01 sec);--------------------…

JSP和Servlet学习笔记1 - 访问配置
1. 访问 WebContent 目录下的 JSP 文件 在 WebContent 目录下的文件可以直接在浏览器中访问。新建一个 test.jsp 文件 <% page language"java" contentType"text/html; charsetISO-8859-1"pageEncoding"ISO-8859-1"%> <!DOCTYPE htm…

unity人物旋转移动代码_Unity3D研究院之脚本实现模型的平移与旋转(六)
123 说:雨松大大,有个问题想请教一下,我用UNET构建了个小场景,在电脑上可以客户端可以连接到服务器,Windows和Linux都可以,发布到安卓缺连不了,这是问什么呢说:求教一下,…

博客园的第一篇博文
以后所有技术相关的文章都记录在博客园啦,加油!转载于:https://www.cnblogs.com/dabenniu/p/6337549.html

java后台分页插件怎么写_Java分页技术(从后台传json到前台解析显示)
0 这是一篇我在初学习过程中,遇到的动态数据分页显示的问题,前台采用Ajax传给后台,后台在访问数据库取出分页数据再转换为json格式传递给前台,前台再解析显示到表格中。在此写出我在做的过程中遇到的问题,可以让其他人…

c 应用程序mysql_MySQL C 语言应用程序接口开发教程
从数据库中取回数据在这个实例中我们从表中取回数据。步骤:(1)创建连接(2)执行查询(3)获取结果集(4)提取所有可用的记录(5)释放结果集实例程序打印 writers 表中所有的记录(姓名)。#include #include int main(int argc, char * argv[]){MYSQL * conn;MYSQL_RES * r…

GreenPlum学习笔记:基础知识
一、介绍 GreenPlum分布式数据仓库,大规模并行计算技术。 无共享/MPP核心架构Greenplum数据库软件将数据平均分布到系统的所有节点服务器上,所以节点存储每张表或表分区的部分行,所有数据加载和查询都是自动在各个节点服务器上并行运行&…

java 套接字关联的通道_Java 通道教程 – NIO 2.0
# Java 通道教程 – NIO 2.0> 原文: [https://howtodoinjava.com/java7/nio/java-nio-2-0-channels/](https://howtodoinjava.com/java7/nio/java-nio-2-0-channels/)通道是继[**缓冲区**](//howtodoinjava.com/java-7/nio/java-nio-2-0-working-with-buffers/ &…

虚拟机ubuntu14.04系统设置静态ip
ubuntu14.04 设置静态ip vim /etc/network/interfaces 原来只有 auto lo iface lo inet loopback 修改成如下: auto lo iface lo inet loopbackauto eth0 iface eth0 inet static #静态ip address 192.168.1.6 #要设置的ip gateway 192.168.1.1 #这…

高职信息安全比赛攻防思路_30.LNGZ2020-30:2020年辽宁省职业院校技能大赛(高职组)“信息安全管理与评估”赛项规程...
12020年辽宁省职业院校技能大赛(高职组)信息安全管理与评估赛项规程一、赛项名称赛项编号:LNGZ2020-30赛项名称:信息安全管理与评估英文名称:Information Security Management and Evaluation赛项组别:高职组赛项归属:…

oracle rac对心跳要求_关于心跳网络引起的Oracle RAC的节点驱逐(不是实例驱逐)...
关于心跳网络引起的Oracle RAC的节点驱逐(不是实例驱逐)问:假设如下场景:4个节点rac,心跳线走的是千m网络交换机,若是该千M网络交换机断电,我想知道crs的驱逐节点的算法是怎么样的?Oracle 大连 GCS 答复&am…

php 字符串数组转数组对象_php怎么将数组转成对象?
php将数组转成对象的方法:1、使用数据类型转换,在数组变量前添加“(Object)”来将数组转成对象。2、先使用json_encode()函数将数组转换为json字符串;然后使用json_decode()函数将json字符串转换成对象。php将数组转成对象有时候数组要转为对…

如何在Win7电脑上增加新磁盘分区?
我们在重装好系统Win7系统后有时会碰到需要新建磁盘分区的情况,这时我们再重装系统进行磁盘分区就有些过于麻烦了,其实我们可以利用Win7系统自身的磁盘管理功能来新建一个磁盘分区。下面好系统重装助手就来介绍一下好系统Win7系统电脑磁盘新建分区的方法…

WIn7下Ubuntu 14.04 安装
1. 在Windows下下载Ubuntu14.04的ISO镜像,解压 2. 打开wubi.exe,填写用户名,密码等相关信息,在这里需要注意的是,磁盘空间最好选到最大(30G),执行安装 3. 按照提示,重启系…

cimiss数据_CIMISS,你太优秀了!
原标题:CIMISS,你太优秀了!本周二的时候小据给大家带来了一位新朋友那便是CIMISS你真的了解它吗?一文读懂CIMISS(戳上面的链接进行回顾)今天我们继续了解一起探讨它能够为我们带来哪些好处天气业务“一站式”数据供给自2014年8月以…

python3 tkinter电子书_python3 tkinter实现添加图片和文本
本文在前面文章基础上介绍tkinter添加图片和文本,在这之前,我们需要安装一个图片库,叫Pillow,这个需要下载exe文件,根据下面图片下载和安装。下载完后直接双击安装exe,默认点击下一步,直到安装完…

序列化和反序列化实现
1. 什么是序列化? 程序员在编写应用程序的时候往往需要将程序的某些数据存储在内存中,然后将其写入文件或是将其传输到网络中的另一台计算机上以实现通讯。这个将程序数据转换成能被存储并传输的格式的过程被称为序列化(serialization&#x…

linux source命令
source filename 与 sh filename 及./filename执行脚本的区别在那里呢?1.当shell脚本具有可执行权限时,用sh filename与./filename执行脚本是没有区别得。./filename是因为当前目录没有在PATH中,所有"."是用来表示当前目录的。2.sh…

centos7 nginx配置php7,centos7安装并配置nginx+php,centos7nginx
centos7安装并配置nginxphp,centos7nginxcentos7安装并配置nginxphp安装nginxyum install nginx设置nginx开启起动systemctl start nginx测试访问http://你的域名或IP/查看nginx安装位置whereis nginxnginx: /usr/sbin/nginx /etc/nginx /usr/share/nginx /usr/shar…

host ntrip 千寻rtk_什么是千寻知寸cors账号?它提供的定位服务精度如何?使用时需要注意哪些问题?...
千寻知寸cors账号FindCM:基于RTK技术的厘米级差分数据播发服务,终端设备收到差分数据后,结合自己的卫星观测数据进行高精度定位解算,在观测环境良好的情况下,统计精度可以达到水平2~5厘米,高程2~8厘米。由于…

python创建图片对应的csv格式_Python:如何从csv文件创建图形节点和边?
你可以用另一个COLATIC和COLATIC来建立一个COLATIC/COLATIC。然后将图“投影”到datetime节点上—如果两个datetime都链接到ColA/ColC节点,则在它们之间创建一个链接。在下面的代码展示了一种创建无向图的方法。我不明白你的例子里的指示是什么意思。在import csvim…

卡尺测量的最小范围_工厂车间里常用的测量仪器使用方法介绍,你都会用吗?...
一、测量器具的分类 测量器具是一种具有固定形态、用以复现或提供一个或多个已知量值的器具。按用途的不同量具可分为以下几类:1. 单值量具只能体现一个单一量值的量具。可用来校对和调整其它测量器具或作为标准量与被测量直接进行比较,如量块、角度量块…
codeblocks使用指南
文章目录目录创建c/c项目调试codeblocks快捷键目录 创建c/c项目 左上角File->new->project,然后在弹出的对话框中找到Console application点击Go,然后不断Next,中间的除了项目名和项目地址其他默认即可。 然后在左侧工程目录中点开main文件即可Coding了。&…

php变量 标签,html标签如何使用php中的变量
html标签中使用php变量,提示:Undefined index: uid in /var/www//list.php,list.php的具体代码如下:require redis.php;for ($i0; $i < ($redis->get("userid")) ; $i){$data[] $redis->hgetall("user:&…

Shell基础命令之echo
echo命令的功能是在显示器上显示一段文字,一般起到一个提示的作用。该命令的一般格式为: echo [ -n ] 字符串其中选项n表示输出文字后不换行;字符串能加引号,也能不加引号。用echo命令输出加引号的字符串时,将字符串原…