首页

文章

MySql中查询语句实现分页功能

发布网友 发布时间:2022-04-19 21:50

我来回答

11个回答

热心网友 时间:2022-04-07 16:33

pageNow代表当前页面,第一页。

第一部分:看一下分页的基本原理:

对上面的mysql语句说明:limit 10000,20的意思扫描满足条件的10020行,扔掉前面的10000行,返回最后的20行,问题就在这里,如果是limit 100000,100,需要扫描100100行,在一个高并发的应用里,每次查询需要扫描超过10W行,性能肯定大打折扣。文中还提到limit n性能是没问题的,因为只扫描n行。

第二部分:根据雅虎的几位工程师带来了一篇Efficient Pagination Using MySQL的报告内容扩展:在文中提到一种clue的做法,给翻页提供一些线索,比如还是SELECT * FROM message ORDER BY id DESC,按id降序分页,每页20条,当前是第10页,当前页条目id最大的是1020,最小的是1000,如果我们只提供上一页、下一页这样的跳转(不提供到第N页的跳转),那么在处理上一页的时候SQL语句可以是:

处理下一页的时候SQL语句可以是:

不管翻多少页,每次查询只扫描20行。

缺点是只能提供上一页、下一页的链接形式,但是我们的产品经理非常喜欢“上一页 1 2 3 4 5 6 7 8 9 下一页”这样的链接方式,怎么办呢?

如果LIMIT m,n不可避免的话,要优化效率,只有尽可能的让m小一下,我们扩展前面的clue做法,还是SELECT * FROM message ORDER BY id DESC,按id降序分页,每页20条,当前是第10页,当前页条目id最大的是2519,最小的是2500;

当是第10页的SQL如下:

比如要跳到第9页,SQL语句可以这样写:

比如要跳到第8页,SQL语句可以这样写:

原理还是一样,记录住当前页id的最大值和最小值,计算跳转页面和当前页相对偏移,由于页面相近,这个偏移量不会很大,这样的话m值相对较小,大大减少扫描的行数。其实传统的limit m,n,相对的偏移一直是第一页,这样的话越翻到后面,效率越差,而上面给出的方法就没有这样的问题。

热心网友 时间:2022-04-07 17:51

不要把表达式放到SQL里面的limit字句中,需要先计算为数值,例如:
select * from userdetail where userid limit 0,20

热心网友 时间:2022-04-07 19:25

"select * from userdetail where userid limit " +((pageNow-1)*pageSize)+","+pageSize;

limit 后没有空格,导致与数据连在了一起,这是个很容易错的。

热心网友 时间:2022-04-07 21:17

select * from userdetail limit (pageNow-1)*pageSize,pageSize; 不需要where ,但是最后按照某一项进行升序或降序排列 eg: select * from userdetail ORDER BY userid limit (pageNow-1)*pageSize,pageSize;

热心网友 时间:2022-04-07 23:25

两个查询sql组装分页

两个查询sql组装分页

热心网友 时间:2022-04-08 01:49

limit后面俩参数在程序里计算出来然后拼串比如pagesize为50,当前pagenum为1,自己先在代码里计算出此时当前页要取的是0,50,然后带到SQL语句里,如果是2,则为50,50,这块得用JAVA的程序里来计算

当然mysql也提供参数代入,不过一般那是存储过程或者函数里面才用到的,在这儿就直接取最好

话说直接where userid limit 0,50不报错么?我一般都是where 1=1 order by userid limit 0,50

热心网友 时间:2022-04-08 04:31

select * from userdetail --where userid-- limit (pageNow-1)*pageSize,pageSize;

where userid没有给userid赋值。

limit后面(pageNow-1)*pageSize和pageSize在程序中计算好(如果加引号的话)如下:

“select * from userdetail where userid=? limit  ”+ (pageNow-1)*pageSize+“,”+pageSize;

注意空格,回答的也许不是很完整,凑合看。

热心网友 时间:2022-04-08 07:29

//定义变量
private int pageSize = 3;
private int rowCount = 0;// 从数据库查询得到
private int pageCount = 0;// 该值通过pageSize和rowCount计算

//得到分页列表总页数
public int getPageCount() {
try {
ct = new ConnDB().getConn();
sm = ct.createStatement();
// 4.查询
rs = sm.executeQuery("select count(*) from user ");
// 请注意一定要re.nest()
if (rs.next()) {
rowCount = rs.getInt(1);
}
// 计算pageCount
if (rowCount % pageSize == 0) {
pageCount = rowCount / pageSize;
} else {
pageCount = rowCount / pageSize + 1;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
this.close();
}
return pageCount;
}

//获得标志位
String flag=request.getParameter("flag");
//如果是分页
if(flag.equals("fengye")){
// 得到用户希望的pageNow;
System.out.println("分页使用servlet技术");
String s_pageNow = request.getParameter("pageNow");
try {
int pageNow = Integer.parseInt(s_pageNow);
//调用UserBeanCL
UserBeanCL ubc=new UserBeanCL();
ArrayList al=ubc.getUserByPage(pageNow);
int pageCount=ubc.getPageCount();
//将al,pageCount,pageCount放入request
request.setAttribute("result",al);
request.setAttribute("pageCount", pageCount+"");
request.setAttribute("pageNow", pageNow+"");
//重新跳转会wel.jsp
request.getRequestDispatcher("wel.jsp").forward(request, response);
} catch (Exception e) {
e.printStackTrace();
}
}

//从request中取出pageNow
int pageNow=Integer.parseInt((String)request.getAttribute("pageNow"));
//上一页
if(pageNow!=1){

out.println("<a href=UserCLServlet?flag=fengye&pageNow=1>首页</a>");
out.println("<a href=UserCLServlet?flag=fengye&pageNow="+(pageNow-1)+">上一页</a>");
}
//得到pageCount
String S_pageCount=(String)request.getAttribute("pageCount");

int pageCount=Integer.parseInt(S_pageCount);

for(int i=1;i<=pageCount;i++){

out.println("<a href=UserCLServlet?flag=fengye&pageNow="+i+">["+i+"]</a>");
}
if(pageNow!=pageCount){
out.println("<a href=UserCLServlet?flag=fengye&pageNow="+(pageNow+1)+">下一页</a>");
out.println("<a href=UserCLServlet?flag=fengye&pageNow="+pageCount+">尾页</a>");
}

%>

热心网友 时间:2022-04-08 10:43

计算出了具体值再去查询吧

热心网友 时间:2022-04-08 14:15

很多应用往往只展示最新或最热门的几条记录,但为了旧记录仍然可访问,所以就需要个分页的导航栏。然而,如何通过MySQL更好的实现分页,始终是比较令人头疼的问题。虽然没有拿来就能用的解决办法,但了解数据库的底层或多或少有助于优化分页查询。

我们先从一个常用但性能很差的查询来看一看。

SELECT *
FROM city
ORDER BY id DESC
LIMIT 0, 15

这个查询耗时0.00sec。So,这个查询有什么问题呢?实际上,这个查询语句和参数都没有问题,因为它用到了下面表的主键,而且只读取15条记录。

CREATE TABLE city (
id int(10) unsigned NOT NULL AUTO_INCREMENT,
city varchar(128) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB;

真正的问题在于offset(分页偏移量)很大的时候,像下面这样:

SELECT *
FROM city
ORDER BY id DESC
LIMIT 100000, 15;

上面的查询在有2M行记录时需要0.22sec,通过EXPLAIN查看SQL的执行计划可以发现该SQL检索了100015行,但最后只需要15行。大的分页偏移量会增加使用的数据,MySQL会将大量最终不会使用的数据加载到内存中。就算我们假设大部分网站的用户只访问前几页数据,但少量的大的分页偏移量的请求也会对整个系统造成危害。*意识到了这一点,但*并没有为了每秒可以处理更多的请求而去优化数据库,而是将重心放在将请求响应时间的方差变小。

对于分页请求,还有一个信息也很重要,就是总共的记录数。我们可以通过下面的查询很容易的获取总的记录数。

SELECT COUNT(*)
FROM city;

然而,上面的SQL在采用InnoDB为存储引擎时需要耗费9.28sec。一个不正确的优化是采用 SQL_CALC_FOUND_ROWS,SQL_CALC_FOUND_ROWS 可以在能够在分页查询时事先准备好符合条件的记录数,随后只要执行一句 select FOUND_ROWS(); 就能获得总记录数。但是在大多数情况下,查询语句简短并不意味着性能的提高。不幸的是,这种分页查询方式在许多主流框架中都有用到,下面看看这个语句的查询性能。

SELECT SQL_CALC_FOUND_ROWS *
FROM city
ORDER BY id DESC
LIMIT 100000, 15;

这个语句耗时20.02sec,是上一个的两倍。事实证明使用 SQL_CALC_FOUND_ROWS 做分页是很糟糕的想法。
下面来看看到底如何优化。文章分为两部分,第一部分是如何获取记录的总数目,第二部分是获取真正的记录。

高效的计算行数

如果采用的引擎是MyISAM,可以直接执行COUNT(*)去获取行数即可。相似的,在堆表中也会将行数存储到表的元信息中。但如果引擎是InnoDB情况就会复杂一些,因为InnoDB不保存表的具体行数。

我们可以将行数缓存起来,然后可以通过一个守护进程定期更新或者用户的某些操作导致缓存失效时,执行下面的语句:

SELECT COUNT(*)
FROM city
USE INDEX(PRIMARY);

获取记录

下面进入这篇文章最重要的部分,获取分页要展示的记录。上面已经说过了,大的偏移量会影响性能,所以我们要重写查询语句。为了演示,我们创建一个新的表“news”,按照时事性排序(最新发布的在最前面),实现一个高性能的分页。为了简单,我们就假设最新发布的新闻的Id也是最大的。

CREATE TABLE news(
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(128) NOT NULL
) ENGINE=InnoDB;

一个比较高效的方式是基于用户展示的最后一个新闻Id。查询下一页的语句如下,需要传入当前页面展示的最后一个Id。

SELECT *
FROM news WHERE id < $last_id
ORDER BY id DESC
LIMIT $perpage

查询上一页的语句类似,只不过需要传入当前页的第一个Id,并且要逆序。

SELECT *
FROM news WHERE id > $last_id
ORDER BY id ASC
LIMIT $perpage

上面的查询方式适合实现简易的分页,即不显示具体的页数导航,只显示“上一页”和“下一页”,例如博客中页脚显示“上一页”,“下一页”的按钮。但如果要实现真正的页面导航还是很难的,下面看看另一种方式。

SELECT id
FROM (
SELECT id, ((@cnt:= @cnt + 1) + $perpage - 1) % $perpage cnt
FROM news
JOIN (SELECT @cnt:= 0)T
WHERE id < $last_id
ORDER BY id DESC
LIMIT $perpage * $buttons
)C
WHERE cnt = 0;

通过上面的语句可以为每一个分页的按钮计算出一个offset对应的id。这种方法还有一个好处。假设,网站上正在发布一片新的文章,那么所有文章的位置都会往后移一位,所以如果用户在发布文章时换页,那么他会看见一篇文章两次。如果固定了每个按钮的offset Id,这个问题就迎刃而解了。Mark Callaghan发表过一篇类似的博客,利用了组合索引和两个位置变量,但是基本思想是一致的。

如果表中的记录很少被删除、修改,还可以将记录对应的页码存储到表中,并在该列上创建合适的索引。采用这种方式,当新增一个记录的时候,需要执行下面的查询重新生成对应的页号。

SET p:= 0;
UPDATE news SET page=CEIL((p:= p + 1) / $perpage) ORDER BY id DESC;

当然,也可以新增一个专用于分页的表,可以用个后台程序来维护。

UPDATE pagination T
JOIN (
SELECT id, CEIL((p:= p + 1) / $perpage) page
FROM news
ORDER BY id
)C
ON C.id = T.id
SET T.page = C.page;

现在想获取任意一页的元素就很简单了:

SELECT *
FROM news A
JOIN pagination B ON A.id=B.ID
WHERE page=$offset;

还有另外一种与上种方法比较相似的方法来做分页,这种方式比较试用于数据集相对小,并且没有可用的索引的情况下—比如处理搜索结果时。在一个普通的服务器上执行下面的查询,当有2M条记录时,要耗费2sec左右。这种方式比较简单,创建一个用来存储所有Id的临时表即可(这也是最耗费性能的地方)。

CREATE TEMPORARY TABLE _tmp (KEY SORT(random))
SELECT id, FLOOR(RAND() * 0x8000000) random
FROM city;

ALTER TABLE _tmp ADD OFFSET INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, DROP INDEX SORT,ORDER BY random;

接下来就可以向下面一样执行分页查询了。

SELECT *
FROM _tmp
WHERE OFFSET >= $offset
ORDER BY OFFSET
LIMIT $perpage;

简单来说,对于分页的优化就是。。。避免数据量大时扫描过多的记录。

热心网友 时间:2022-04-08 18:03

把where userid去掉,
玉米仁子饭产自哪里 中国期货交易所的交易品种有哪些? 历史要怎么读,有啥诀窍 高中历史诀窍 年终会活动策划方案 深度解析:第一财经回放,探索财经新风向 逆水寒手游庄园怎么邀请好友同住 逆水寒手游 逆水寒不同区可以一起组队吗? 逆水寒手游 逆水寒怎么进入好友世界? 逆水寒手游 逆水寒怎么去别人的庄园? 使用puppeteer实现将htmll转成pdf 内卷时代下的前端技术-使用JavaScript在浏览器中生成PDF文档 【译】将HTML转为PDF的几种实现方案 变形金刚08动画怎么样 变形金刚08动画的问题 变形金刚08动画日语版剧情介绍 高分!换显卡nvidia控制面板被我卸了,重新安装显卡驱动后没了nvidia控... 我的nvidia控制面板被卸载了 怎么找回啊 卸载后 这个画面看着很奇怪_百 ... 李卓彬工作简历 林少明工作简历 广东工业职业技术学院怎么样 郑德涛任职简历 唐新桂个人简历 土地入股的定义 ups快递客服电话24小时 贷款记录在征信保留几年? 安徽徽商城有限公司公司简介 安徽省徽商集团新能源股份有限公司基本情况 安徽省徽商集团有限公司经营理念 2019哈尔滨煤气费怎么有税? 快手删除的作品如何恢复 体育理念体育理念 有关体育的格言和理念 什么是体育理念 万里挑一算彩礼还是见面礼 绿萝扦插多少天后发芽 绿萝扦插多久发芽 扦插绿萝多久发芽 炖牛排骨的做法和配料 网络诈骗定罪标准揭秘 “流水不争先”是什么意思? mc中钻石装备怎么做 为什么我的MC里的钻石块是这样的?我想要那种。是不是版本的问题?如果是... 带“偷儿”的诗句 “君不见巴丘古城如培塿”的出处是哪里 带“奈何”的诗句大全(229句) 里翁行()拼音版、注音及读音 带“不虑”的诗句 “鲁肃当年万人守”的出处是哪里 无尘防尘棚 结合MySQL数据库,如何实现分页功能? mysql如何做分页查询? 考摩托车驾驶证一般是多少钱左右? 摩托车驾驶证怎么考和考试流程 现在摩托车驾照怎么考 摩托车驾驶证如何考? 考摩托车驾照都要走哪些程序 摩托车驾驶证怎么考? 摩托车驾照考试流程 如何考取摩托车驾驶证 考摩托车驾驶证怎么考 想考摩托车驾照大概走什么流程? 考摩托车驾照的流程 摩托车考驾照该怎么考,需要什么流程? 西昌那里能办摩托车驾照? 西昌航天驾驶可以考摩托驾照吗 西昌有没有考摩托驾照 wpsword怎么做组织架构图 企业组织架构图模板 WORD 谢谢 请问QQ被盗了怎么办? qq聊天记录怎么才能彻底删除,为什么我的电手机上... mysql 数据量大的表如何做分页查询 Mysql分页查询 Mysql 数据库怎么实现分页,要说的通俗一点儿 mysql分页查询语句怎么写 mysql 数据库 分表后 怎么进行分页查询? mysql数据库分页 mysql里分页查询怎么写 mysql如何实现分页 mybatis+mysql怎么分页查询 mysql按条件分页查询的语句怎么写啊? mysql与oracle的分页查询语句? oracle和mysql分页查询问题 求教,mysql千万级数据多表查询做分页该如何优化 苹果12怎么显示手机电量 奥币等于多少人民币? 1奥币等于多少人民币 现在澳币对人民币是多少 澳币如何换算成人民币? 100澳币换算成人民币是多少钱?
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com