﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-liuzheng-文章分类-SQL Server</title><link>http://www.blogjava.net/liuzheng/category/24702.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 21 Sep 2007 09:47:18 GMT</lastBuildDate><pubDate>Fri, 21 Sep 2007 09:47:18 GMT</pubDate><ttl>60</ttl><item><title>分页技术在sql server数据库上的底层实现</title><link>http://www.blogjava.net/liuzheng/articles/146698.html</link><dc:creator>刘铮 </dc:creator><author>刘铮 </author><pubDate>Thu, 20 Sep 2007 02:30:00 GMT</pubDate><guid>http://www.blogjava.net/liuzheng/articles/146698.html</guid><wfw:comment>http://www.blogjava.net/liuzheng/comments/146698.html</wfw:comment><comments>http://www.blogjava.net/liuzheng/articles/146698.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liuzheng/comments/commentRss/146698.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liuzheng/services/trackbacks/146698.html</trackback:ping><description><![CDATA[<span class="t18">&nbsp;
<p>1.&#8220;俄罗斯存储过程&#8221;的改良版</p>
<p>CREATE procedure pagination1<br />
(@pagesize int, --页面大小，如每页存储20条记录<br />
@pageindex int --当前页码)<br />
as set nocount on</p>
<p>begin</p>
<p>declare @indextable table(id int identity(1,1),nid int) --定义表变量<br />
declare @PageLowerBound int --定义此页的底码<br />
declare @PageUpperBound int --定义此页的顶码</p>
<p>set @PageLowerBound=(@pageindex-1)*@pagesize<br />
set @PageUpperBound=@PageLowerBound+@pagesize<br />
set rowcount @PageUpperBound<br />
insert into @indextable(nid) select gid from TGongwen where fariqi &gt;dateadd(day,-365,getdate()) order by fariqi desc<br />
select O.gid,O.mid,O.title,O.fadanwei,O.fariqi from TGongwen O,@indextable t where O.gid=t.nid<br />
and t.id&gt;@PageLowerBound and t.id&lt;<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#61;&#64;&#80;&#97;&#103;&#101;&#85;&#112;&#112;&#101;&#114;&#66;&#111;&#117;&#110;&#100;">=@PageUpperBound</a> order by t.id</p>
<p>end</p>
<p>set nocount off</p>
<p>文章中的点评： </p>
<p>以上存储过程运用了SQL SERVER的最新技术――表变量。应该说这个存储过程也是一个非常优秀的分页存储过程。当然，在这个过程中，您也可以把其中的表变量写成临时表：CREATE TABLE #Temp。但很明显，在SQL SERVER中，用临时表是没有用表变量快的。所以笔者刚开始使用这个存储过程时，感觉非常的不错，速度也比原来的ADO的好。但后来，我又发现了比此方法更好的方法。 </p>
<p>从感觉上讲，效率不是太高。</p>
<p><br />
2. not in 的方法： <br />
从publish 表中取出第 n 条到第 m 条的记录：</p>
<p>SELECT TOP m-n+1 * FROM publish WHERE (id NOT IN (SELECT TOP n-1 id FROM publish))</p>
<p>id 为publish 表的关键字</p>
<p>文章中的点评： </p>
<p>我当时看到这篇文章的时候，真的是精神为之一振，觉得思路非常得好。等到后来，我在作办公自动化系统（ASP.NET+ C#＋SQL SERVER）的时候，忽然想起了这篇文章，我想如果把这个语句改造一下，这就可能是一个非常好的分页存储过程于是我就满网上找这篇文章，没想到，文章还没找到，却找到了一篇根据此语句写的一个分页存储过程，这个存储过程也是目前较为流行的一种分页存储过程。</p>
<p>使用了 not in 而 not in 是无法使用索引的，所以从效率上讲还是差了一点。 </p>
<p><br />
3. max 的方法：</p>
<p>select top 页大小 * from table1 where id&gt;<br />
&nbsp;(select max (id) from<br />
&nbsp;(select top ((页码-1)*页大小) id from table1 order by id) as T)<br />
&nbsp;order by id</p>
<p>文章中的点评： </p>
<p>我们知道，几乎任何字段，我们都可以通过max(字段)或min(字段)来提取某个字段中的最大或最小值，所以如果这个字段不重复，那么就可以利用这些不重复的字段的max或min作为分水岭，使其成为分页算法中分开每页的参照物。在这里，我们可以用操作符&#8220;&gt;&#8221;或&#8220;&lt;&#8221;号来完成这个使命，使查询语句符合SARG形式。如：<br />
Select top 10 * from table1 where id&gt;200</p>
<p>这个就高高效了一点。但是不清楚 max的工作原理，不知道它的性能如何。 </p>
<p>心得：</p>
<p>1、追求高效的翻页算法 —— 定位法。</p>
<p>declare @pageSize int --返回一页的记录数<br />
declare @CurPage int --页号（第几页）0：第一页；-1最后一页。</p>
<p>declare @Count int<br />
declare @id int</p>
<p>set @pageSize=10<br />
set @CurPage =1</p>
<p>--定位<br />
if @CurPage = -1<br />
begin<br />
&nbsp;--最后一页<br />
&nbsp;set rowcount @pageSize<br />
&nbsp;select @id=newsID from newsTemp order by newsID<br />
end</p>
<p>if @CurPage &gt; 0<br />
begin<br />
&nbsp;set @Count = @pageSize * (@CurPage -1) + 1<br />
&nbsp;set rowcount @Count<br />
&nbsp;select @id=newsID from newsTemp order by newsID desc<br />
end</p>
<p>--返回记录<br />
set rowcount @pageSize<br />
select * from newsTemp where newsID &lt;<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#61;&#64;&#105;&#100;">=@id</a> order by newsID desc</p>
<p>set rowcount 0</p>
<p><br />
思路：就是上面的算法的延续，就是说呢避免使用 not in 和 max 的方法。也就是这个思路：Select top 10 * from table1 where id&gt;200，定位 —— 就是说要找到&#8220;临界点&#8221;，分页的临界点。找到了之后剩下的事情就好办了。</p>
<p>缺点：单字段排序、排序字段的值不能重复（不是绝对不能重复，可以有少量的重复）。</p>
<p><br />
2、通用法 —— 颠颠倒倒法</p>
<p>有的时候&#8220;定位法&#8221;的缺点是不可以接受的，但是没有关系，可以用这个的。</p>
<p>select * from table where id in <br />
(<br />
&nbsp;select top 10 ID from <br />
&nbsp;(<br />
&nbsp;select top 20 ID,addedDate from table <br />
&nbsp;order by addedDate desc<br />
&nbsp;) as aa order by addedDate<br />
)<br />
order by addedDate desc</p>
<p>ID 是主键，addedDate 是排序字段。</p>
<p>缺点：必须有主键。</p>
</span><!--正文内容结束-->
<img src ="http://www.blogjava.net/liuzheng/aggbug/146698.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liuzheng/" target="_blank">刘铮 </a> 2007-09-20 10:30 <a href="http://www.blogjava.net/liuzheng/articles/146698.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>