一个关于分页的面试题
在网上看到面试中考分页的帖子,结合自己的想法,集合一下,欢迎讨论。
分页是各式各样系统开发过程中必不可少的环节,普通web应用数据量小、访问量小,分页可以用简单的方式来实现,一般是通过startrow+pagenum来实现,甚至可以提前生成静态页面,这样数据库基本没有压力,缺点是数据变动时要重新生成所有列表页,而且不能实时显示数据的变化。
不过还好的是对于大多数的应用能够实现需求即可,不必过多考虑优化。
互联网公司的海量数据,情况就变得不一样了,更多考虑的是性能和效率,加载速度提高一点点,就意味着用户体验的提升,用户体验决定着产品的未来。
因此我们可以看到数据量变大的情况下一个高效的分页变的重要程度,分页面试能够体现面试者是否处理过大量数据,没处理过也能够体现其面试时处理问题的思考和应变能力。
不管什么方法做分页,它都离不开数据库的支持,优化原则是尽量减少扫描数据库中记录的条数。
常用的关系数据库mysql和oracle为例:mysql分页依赖于limit,oracle分页使用rownum实现。
mysql分页方法?
mysql分页的核心语句:
1 |
select * from user order by id dest limit 0,10; |
先看一下分页的基本原理(CSDN那个百万级数据库来测试!):
SELECT * FROM csdn
ORDER BY id DESC LIMIT 100000,2000;
耗时: 0.813ms
分析:对上面的mysql语句说明:limit 100000,2000的意思扫描满足条件的102000行,扔掉前面的100000行,返回最后的2000行。
问题就在这里,如果是limit 100000,20000,需要扫描120000行,在一个高并发的应用里,每次查询需要扫描超过100000行,性能肯定大打折扣。
在《efficient pagination using mysql》中提出的clue方式。
利用clue方法,给翻页提供一些线索,比如还是SELECT * FROM csdn
order by id desc,按id降序分页,每页2000条,当前是第50页,当前页条目id最大的是102000,最小的是100000。如果我们只提供上一页、下一页这样的跳转(不提供到第N页的跳转)。
那么在处理上一页的时候SQL语句可以是:
SELECT * FROM csdn
WHERE id<=102000 ORDER BY id DESC LIMIT 2000; #上一页
耗时:0.015ms
处理下一页的时候SQL语句可以是:
SELECT * FROM csdn
WHERE id>102000 ORDER BY id ASC LIMIT 2000; #下一页
耗时:0.015ms
这样,不管翻多少页,每次查询只扫描20行。效率大大提高了!
但是,这样分页的缺点是只能提供上一页、下一页的链接形式。
oracle如何分页?
oracle分页的核心:
1 2 3 4 5 6 7 8 9 10 11 |
SELECT * FROM (SELECT T1.*, ROWNUM rn FROM (SELECT * FROM testTable ORDER BY id DESC) T1 WHERE ROWNUM <= 20) WHERE rn > 0; |
大量数据时oracle分页语句的优化(通过rownum和rowid来进行分页),如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
SELECT t1.* FROM testTable t1, (SELECT rid FROM (SELECT ROWNUM rn, t.rid FROM (SELECT ROWID rid FROM testTable WHERE 1 = 1) t WHERE ROWNUM <= 20) WHERE rn > 0) t2 WHERE 1 = 1 AND t1.ROWID = t2.rid; |
不错,在数据量较大的场景下也是一种不错的解决办法
这个首先要考虑的是
1.1000万的数据里面实际只有不到20万是最近要访问的,就像淘宝商品目录(用户不会一次加载2000条数据 ,更不会翻到1000页以后)
2.1000万的数据基本不会在一个列表里面,就像京东的商品没有汇总在一个目录而是划分在不同的目录,这样就方便了我们分库分表。
总之,首先考虑业务逻辑,在具体到实现。
需要注意,在实际项目中,自增id不一定是连续的,可能因为某些原因会删除数据,导致id不连续
赞。。。。。博客是wordpress搭建的?
是的