网上关于分页有大堆各种各样的,有人说这个这个处理大数据性能好,有人说那个性能好,听别人说没啥用,自己测试下才知道,但是我只测试除了第一个在查询分页后段的时候真的是不行,其他的在下面的测试中是没问题,也许是下面的例子并不能真实的测出,本来是实力有限,欢迎批评指出, 然后有集中分页方式,然后下面有几种分页方式在稍微复杂点的查询面前,你就会想死,所以就算性能再好写我也是不太喜欢用的
-
首先先创建两张简单测试表,student, class
create table student
(
sno int ,
cno int ,
sname VARCHAR(200)
);
create table class
(
cno int ,
cname VARCHAR(200)
);
-
student 插入100万条数据,插入脚本来之 这里
--随机插入100万数据
DECLARE @LN VARCHAR(300),@MN VARCHAR(200),@FN VARCHAR(200)
DECLARE @LN_N INT,@MN_N INT,@FN_N INT
SET @LN='李王张刘陈杨黄赵周吴徐孙朱马胡郭林何高梁郑罗宋谢唐韩曹许邓萧冯曾程蔡彭潘袁于董余苏叶吕魏蒋田杜丁沈姜范江傅钟卢汪戴崔任陆廖姚方金邱夏谭韦贾邹石熊孟秦阎薛侯雷白龙段郝孔邵史毛常万顾赖武康贺严尹钱施牛洪龚'
SET @MN='德绍宗邦裕傅家積善昌世贻维孝友继绪定呈祥大正启仕执必定仲元魁家生先泽远永盛在人为任伐风树秀文光谨潭棰'
SET @FN='丽云峰磊亮宏红洪量良梁良粮靓七旗奇琪谋牟弭米密祢磊类蕾肋庆情清青兴幸星刑'
SET @LN_N=LEN(@LN)
SET @MN_N=LEN(@MN)
SET @FN_N=LEN(@FN)
DECLARE @TMP VARCHAR(1000),@I INT,@CNO INT
SET @I=1
WHILE @I<1000000
BEGIN
SET @CNO=floor(rand()*100000);
SET @TMP=CAST(SUBSTRING(@LN,CAST(RAND()*@LN_N AS INT),1) AS VARCHAR)
SET @TMP=@TMP+CAST(SUBSTRING(@MN,CAST(RAND()*@MN_N AS INT),1) AS VARCHAR)
SET @TMP=@TMP+CAST(SUBSTRING(@FN,CAST(RAND()*@FN_N AS INT),1) AS VARCHAR)
INSERT INTO student(sno, cno, sname)VALUES(@I, @I % 100000, @TMP)
SET @I=@I+1
end
--向数据库中插入10万条随机姓名记录用于测试(sqlserver2005)
DECLARE @LN VARCHAR(300),@MN VARCHAR(200),@FN VARCHAR(200)
DECLARE @LN_N INT,@MN_N INT,@FN_N INT
SET @LN='李王张刘陈杨黄赵周吴徐孙朱马胡郭林何高梁郑罗宋谢唐韩曹许邓萧冯曾程蔡彭潘袁于董余苏叶吕魏蒋田杜丁沈姜范江傅钟卢汪戴崔任陆廖姚方金邱夏谭韦贾邹石熊孟秦阎薛侯雷白龙段郝孔邵史毛常万顾赖武康贺严尹钱施牛洪龚'
SET @MN='一二三四五六七八九十abcdefghijklmnopqistuvwxyz1234567890'
SET @FN='丽云峰磊亮宏红洪量良梁良粮靓七旗奇琪谋牟弭米密祢磊类蕾肋庆情清青兴幸星刑'
SET @LN_N=LEN(@LN)
SET @MN_N=LEN(@MN)
SET @FN_N=LEN(@FN)
DECLARE @TMP VARCHAR(1000),@I INT
SET @I=100
WHILE @I<100000
BEGIN
SET @TMP=CAST(SUBSTRING(@LN,CAST(RAND()*@LN_N AS INT),1) AS VARCHAR)
SET @TMP=@TMP+CAST(SUBSTRING(@MN,CAST(RAND()*@MN_N AS INT),1) AS VARCHAR)
SET @TMP=@TMP+CAST(SUBSTRING(@FN,CAST(RAND()*@FN_N AS INT),1) AS VARCHAR)
INSERT INTO class(cno,cname)VALUES(@I,@TMP)
SET @I=@I+1
end
-
首先测试最简单的分页不带查询条件,不带表连接, 下面的都是查询第100页的查询语句
-- 取不在前n条的s条数据,n:10w 就挂了
-- s=PageSize,
-- n=PageSize * (PageIndex - 1) 第一页:0 第二页:10 第三页:20
SELECT TOP 10 * FROM student WHERE sno NOT IN
(SELECT TOP 990 sno FROM student ORDER BY sno desc)
ORDER BY sno desc
--查询最后面的n条数据,取后面的s条,然后再数据再倒置数据
-- s=PageSize
-- n=PageSize * PageIndex 第一页:10 第二页:20 第三页:30
SELECT * FROM
(SELECT TOP 10 * FROM
(SELECT TOP 1000 * FROM student ORDER BY sno DESC)
f ORDER BY f.sno asc)
s ORDER BY s.sno DESC
-- 原理同上,只不过最后倒置不是直接Order by查询结果,而是自连接一次倒置,感觉应该更慢吧
SELECT * FROM student w1,
( SELECT TOP 10 sno FROM
( SELECT TOP 1000 sno FROM student ORDER BY sno DESC)
w ORDER BY w.sno ASC )
w2 WHERE w1.sno = w2.sno ORDER BY w1.sno DESC
-- 原理同上只不过表连接改成了 in 的语法
SELECT * FROM student w1 WHERE sno in
(SELECT top 10 sno FROM (
SELECT top 1000 sno FROM student ORDER BY sno DESC)
w ORDER BY w.sno ASC)
ORDER BY w1.sno DESC
-- 查询最后面的s条,row_number正序排序,然后取最后的n条
-- s=PageSize * PageIndex
-- n=PageSize * (PageIndex - 1)
SELECT w2.n, w1.* FROM student w1,
(SELECT TOP 1000 row_number() OVER (ORDER BY sno DESC) n, sno FROM student)
w2 WHERE w1.sno = w2.sno AND w2.n > 990 ORDER BY w2.sno desc
-- 这个方式看起来明显爽很多, 除了后面between and 计算起来比较麻烦一点
-- s=PageSize * (PageIndex - 1) + 1
-- n=PageSize * PageIndex
SELECT * FROM
(SELECT ROW_NUMBER() Over(ORDER BY sno DESC) AS n, * FROM student)
AS t WHERE n between 991 and 1000
-- 查询很麻烦得两个地方都要查
SELECT TOP 10 * FROM student WHERE sname like '%元%' and sno NOT IN
(SELECT TOP 990 sno FROM student where sname like '%元%' ORDER BY sno desc)
ORDER BY sno desc
-- 查询在最内层做就好了
SELECT * FROM
(SELECT TOP 10 * FROM
(SELECT TOP 1000 * FROM student where sname like '%元%' ORDER BY sno DESC)
f ORDER BY f.sno asc)
s ORDER BY s.sno DESC
-- 原理同上
SELECT * FROM student w1,
( SELECT TOP 10 sno FROM
(SELECT TOP 1000 sno FROM student where sname like '%元%' ORDER BY sno DESC)
w ORDER BY w.sno ASC)
w2 WHERE w1.sno = w2.sno ORDER BY w1.sno DESC
-- 原理同上
SELECT * FROM student w1 WHERE sno in
(SELECT top 10 sno FROM
(SELECT top 1000 sno FROM student where sname like '%元%' ORDER BY sno DESC)
w ORDER BY w.sno ASC )
ORDER BY w1.sno DESC
-- 原理同上
SELECT w2.n, w1.* FROM student w1,
(SELECT TOP 1000 row_number() OVER (ORDER BY sno DESC) n, sno FROM student where sname like '%元%')
w2 WHERE w1.sno = w2.sno AND w2.n > 990 ORDER BY w2.sno desc
-- 这个做查询就爽多了
SELECT * FROM
(SELECT ROW_NUMBER() Over(ORDER BY sno DESC) AS n, * FROM student where sname like '%元%')
AS t WHERE n between 991 and 1000
-
然后测试class表跟student表连接,查询class表的cname 字段包含a的,并且吧cname 也要返回
-----------------------------------------------------------------------------------------------------
-- 感觉想死
SELECT TOP 10 * FROM student s inner join class c on s.cno = c.cno WHERE c.cname like '%a%' and sno NOT IN
(SELECT TOP 990 sno FROM student s inner join class c on s.cno = c.cno where c.cname like '%a%' ORDER BY sno desc)
ORDER BY sno desc;
-- 注意下内存有两个cno 所以不要写 * 写 s.*, c.cname 就好了
SELECT * FROM
(SELECT TOP 10 * FROM(
SELECT TOP 1000 s.*, c.cname FROM student s inner join class c on s.cno = c.cno where c.cname like '%a%' ORDER BY s.sno DESC)
f ORDER BY f.sno asc) s ORDER BY s.sno DESC;
-- 返回字段感觉麻烦的要死,想死
SELECT w1.sno, w2.cname, w2.sname, w1.cno FROM student w1,
(SELECT TOP 10 w.cname, w.sname, sno FROM
(SELECT TOP 1000 s.*, c.cname FROM student s inner join class c on s.cno = c.cno where c.cname like '%a%' ORDER BY sno DESC)
w ORDER BY w.sno ASC )
w2 WHERE w1.sno = w2.sno ORDER BY w1.sno DESC;
-- 压根没办法返回class的cname 字段了 因为in 的语法内层值有sno, 除非外面再套一层join, 想死
SELECT * FROM student w1 WHERE sno in
(SELECT top 10 w.sno FROM
(SELECT top 1000 s.sno, s.sname, c.cname FROM student s inner join class c on s.cno = c.cno where c.cname like '%a%' ORDER BY sno DESC )
w ORDER BY w.sno ASC )
ORDER BY w1.sno DESC;
-- 感觉还好
SELECT w2.* FROM student w1,
(SELECT TOP 1000 row_number() OVER (ORDER BY s.sno DESC) n, s.*, c.cname FROM student s inner join class c on s.cno = c.cno where c.cname like '%a%')
w2 WHERE w1.sno = w2.sno AND w2.n > 990 ORDER BY w2.sno desc;
-- 这个做表连接页爽多了
SELECT * FROM
(SELECT ROW_NUMBER() Over(ORDER BY sno DESC) AS n, s.*, c.cname FROM student s inner join class c on s.cno = c.cno where c.cname like '%a%')
AS t WHERE n between 991 and 1000;