[引]:聚集索引与非聚集索引

http://www.cnblogs.com/mythzz/archive/2006/09/01/343714.html

我们的汉语字典的正文本身就是一个聚集索引。比如,我们要查字,就会很自然地翻开字典的前几页,因为的拼音是“an”,而按照拼音排序汉字的字典是以英文字母“a”开头并以“z”结尾的,那么字就自然地排在字典的前部。如果您翻完了所有以“a”开头的部分仍然找不到这个字,那么就说明您的字典中没有这个字;同样的,如果查字,那您也会将您的字典翻到最后部分,因为的拼音是“zhang”。也就是说,字典的正文部分本身就是一个目录,您不需要再去查其他目录来找到您需要找的内容。

  我们把这种正文内容本身就是一种按照一定规则排列的目录称为聚集索引

  如果您认识某个字,您可以快速地从自动中查到这个字。但您也可能会遇到您不认识的字,不知道它的发音,这时候,您就不能按照刚才的方法找到您要查的字,而需要去根据偏旁部首查到您要找的字,然后根据这个字后的页码直接翻到某页来找到您要找的字。但您结合部首目录检字表而查到的字的排序并不是真正的正文的排序方法,比如您查字,我们可以看到在查部首之后的检字表中的页码是672页,检字表中的上面是字,但页码却是63页,的下面是字,页面是390页。很显然,这些字并不是真正的分别位于字的上下方,现在您看到的连续的驰、张、弩三字实际上就是他们在非聚集索引中的排序,是字典正文中的字在非聚集索引中的映射。我们可以通过这种方式来找到您所需要的字,但它需要两个过程,先找到目录中的结果,然后再翻到您所需要的页码。

  我们把这种目录纯粹是目录,正文纯粹是正文的排序方式称为非聚集索引
 

二)何时使用聚集索引或非聚集索引

下面的表总结了何时使用聚集索引或非聚集索引(很重要)。

动作描述

使用聚集索引

使用非聚集索引

列经常被分组排序

返回某范围内的数据

不应

一个或极少不同值

不应

不应

小数目的不同值

不应

大数目的不同值

不应

频繁更新的列

不应

外键列

主键列

频繁修改索引列

不应


 

每个表中只能有一个聚集索引的规则。
 SARG的定义:用于限制搜索的一个操作,因为它通常是指一个特定的匹配,一个值得范围内的匹配或者两个以上条件的AND连接。
 

 介绍完SARG后,我们来总结一下使用SARG以及在实践中遇到的和某些资料上结论不同的经验:

 1Like语句是否属于SARG取决于所使用的通配符的类型

  如:name like ‘张%’ ,这就属于SARG

  而:name like ‘%张’,就不属于SARG。

  原因是通配符%在字符串的开通使得索引无法使用。

2or 会引起全表扫描

  Name=’张三’ and 价格>5000 符号SARG,而:Name=’张三’ or 价格>5000 则不符合SARG。使用or会引起全表扫描。

3、非操作符、函数引起的不满足SARG形式的语句

  不满足SARG形式的语句最典型的情况就是包括非操作符的语句,如:NOT、!=、<>、!<、!>、NOT EXISTS、NOT IN、NOT LIKE等,另外还有函数。下面就是几个不满足SARG形式的例子:
 

4IN 的作用相当与OR
 

5、尽量少用NOT

6exists in 的执行效率是一样的
7、用函数charindex()和前面加通配符%LIKE执行效率一样
8union并不绝对比or的执行效率高
  推荐这里用union来代替or。事实证明,这种说法对于大部分都是适用的。
  如果or两边的查询列是一样的话,那么用union则反倒和用or的执行速度差很多,虽然这里union扫描的是索引,而or扫描的是全表。
9、字段提取要按照需多少、提多少的原则,避免“select *”
10count(*)不比count(字段)
11order by按聚集索引列排序效率最高
12、高效的TOP
三、实现小数据量和海量数据的通用分页显示存储过程
 

CREATE procedure pagination1

(@pagesize int,  --页面大小,如每页存储20条记录

@pageindex int   --当前页码

)

as

set nocount on

begin

declare @indextable table(id int identity(1,1),nid int)  --定义表变量

declare @PageLowerBound int  --定义此页的底码

declare @PageUpperBound int  --定义此页的顶码

set @PageLowerBound=(@pageindex-1)*@pagesize

set @PageUpperBound=@PageLowerBound+@pagesize

set rowcount @PageUpperBound

insert into @indextable(nid) select gid from TGongwen where fariqi >dateadd(day,-365,getdate()) order by fariqi desc

select O.gid,O.mid,O.title,O.fadanwei,O.fariqi from TGongwen O,@indextable t where O.gid=t.nid

and t.id>@PageLowerBound and t.id<=@PageUpperBound order by t.id

end

set nocount off

从publish 表中取出第 n 条到第 m 条的记录:


SELECT TOP m-n+1 *
FROM publish
WHERE (id NOT IN
    (SELECT TOP n-1 id
     FROM publish)) 
 

select top 页大小 *
from table1
where id>
      (select max (id) from
      (select top ((页码-1)*页大小) id from table1 order by id) as T
       )    
  order by id

 

获取指定页的数据

CREATE PROCEDURE pagination3

@tblName   varchar(255),       -- 表名

@strGetFields varchar(1000) = '*',  -- 需要返回的列

@fldName varchar(255)='',      -- 排序的字段名

@PageSize   int = 10,          -- 页尺寸

@PageIndex  int = 1,           -- 页码

@doCount  bit = 0,   -- 返回记录总数, 非 0 值则返回

@OrderType bit = 0,  -- 设置排序类型, 非 0 值则降序

@strWhere  varchar(1500) = ''  -- 查询条件 (注意: 不要加 where)

AS

declare @strSQL   varchar(5000)       -- 主语句

declare @strTmp   varchar(110)        -- 临时变量

declare @strOrder varchar(400)        -- 排序类型

if @doCount != 0

  begin

    if @strWhere !=''

    set @strSQL = "select count(*) as Total from [" + @tblName + "] where "+@strWhere

    else

    set @strSQL = "select count(*) as Total from [" + @tblName + "]"

end 

--以上代码的意思是如果@doCount传递过来的不是0,就执行总数统计。以下的所有代码都是@doCount为0的情况

else

begin

if @OrderType != 0

begin

    set @strTmp = "<(select min"

set @strOrder = " order by [" + @fldName +"] desc"

--如果@OrderType不是0,就执行降序,这句很重要!

end

else

begin

    set @strTmp = ">(select max"

    set @strOrder = " order by [" + @fldName +"] asc"

end

if @PageIndex = 1

begin

    if @strWhere != ''  

    set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ "  from [" + @tblName + "] where " + @strWhere + " " + @strOrder

     else

     set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ "  from ["+ @tblName + "] "+ @strOrder

--如果是第一页就执行以上代码,这样会加快执行速度

end

else

begin

--以下代码赋予了@strSQL以真正执行的SQL代码

set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ "  from ["

    + @tblName + "] where [" + @fldName + "]" + @strTmp + "(["+ @fldName + "]) from (select top " + str((@PageIndex-1)*@PageSize) + " ["+ @fldName + "] from [" + @tblName + "]" + @strOrder + ") as tblTmp)"+ @strOrder

if @strWhere != ''

    set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ "  from ["

        + @tblName + "] where [" + @fldName + "]" + @strTmp + "(["

        + @fldName + "]) from (select top " + str((@PageIndex-1)*@PageSize) + " ["

        + @fldName + "] from [" + @tblName + "] where " + @strWhere + " "

        + @strOrder + ") as tblTmp) and " + @strWhere + " " + @strOrder

end

end  

exec (@strSQL)

GO

将聚集索引建立在:

  1、您最频繁使用的、用以缩小查询范围的字段上;

  2、您最频繁使用的、需要排序的字段上。

posted on 2008-06-27 08:16  Edison Zhu  阅读(578)  评论(0编辑  收藏  举报