日期:2014-05-17  浏览次数:20520 次

来自新手关于分页效率的疑惑
下面有两条查询语句都是查找数据表中第5 到第10条数据的,假设数据量很大,下面两条语句执行起来哪个效率会比较高?各有什么优缺点?
SELECT * FROM (SELECT (row_number() OVER (ORDER BY getdate ()))  AS rownum,* FROM [DataTable]) t1 WHERE  rownum BETWEEN 5 AND 10

SELECT TOP 5 * FROM T_Instrument WHERE id NOT IN (SELECT TOP 5 id FROM [DataTable])

貌似第一条子查询把整张表找出来筛选了,而第二条只把id列找出来筛选了,这样的理解对不对?
还有没不同的写法,效率如何?
欢迎指教!
分页?效率 分页 效率

------解决方案--------------------
top倒腾法 不是这样用的
应该 取倒序的top 5从(取正序的top 10)
------解决方案--------------------
SELECT * FROM (SELECT (row_number() OVER (ORDER BY getdate ()))  AS rownum,* FROM [DataTable]) t1 WHERE  rownum BETWEEN 5 AND 10


应该使用这种写法,最好能够指明排序方式,而不是用getdate()去排序
第二句你用到not in效率要差很多,这个函数会导致多次全表扫描
------解决方案--------------------
呵呵,直接做个试验,进行比较:

--DROP TABLE xx


CREATE TABLE XX(
id INT IDENTITY(1,1) PRIMARY KEY,
v VARCHAR(10))

INSERT INTO xx
VALUES('aaa')
go 1000
--方法1
SELECT *
FROM
(
SELECT *,
       ROW_NUMBER() OVER(ORDER BY id) AS rownum
FROM xx
)t
WHERE rownum BETWEEN 6 AND 10
/*
id v rownum
6 aaa 6
7 aaa 7
8 aaa 8
9 aaa 9
10 aaa 10
*/

--方法2
SELECT TOP 5 * FROM xx 
WHERE id NOT IN (SELECT TOP 5 id FROM xx)
/*
id v
6 aaa
7 aaa
8 aaa
9 aaa
10 aaa
*/

------解决方案--------------------
下面的图是,上面方法1和方法2 的执行计划,从执行计划中,可以很明显的看出,第1个方法的开销占35%,而第2个方法的开销占65%,很明显的,第1中row_number的方法效率更高:



方法1,用了1次聚集索引扫描,而方法2,用了2次聚集索引扫描,而且还用了嵌套循环连接,把2次扫描的结果集关联起来,所以并不是像你所说的,第二种not in的方法不会扫描,其实也好扫描的。
------解决方案--------------------
通过输入set statistics io on 命令,我们可以看到,方法1是逻辑扫描2次,而方法2是扫描了22次,很明显,第2个方法的效率较差:


(5 行受影响)
表 'XX'。扫描计数 1,逻辑读取 2 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

(5 行受影响)
表 'XX'。扫描计数 2,逻辑读取 22 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。