在SQL2005中有如下的分页SQL语句,作用在对视图View_Product(共有5W多记录)中获取一个特定范围内的行的记录(这里是从47985 到48000 ),本人在视图上已经对 pagerrank0和releaseTime建立了非聚集索引,但下面的SQL语句在执行时尽然要18秒左右,SQL语句如下:SELECT *
   FROM (SELECT ROW_NUMBER() OVER(ORDER BY pagerrank0 desc,releaseTime desc) AS rownum, 
     *
      FROM View_product  WHERE isPassAudit='true' and pagerRank0>0 ) AS D
    WHERE isPassAudit='true' and pagerRank0>0  AND rownum BETWEEN 47985 AND 48000 ORDER BY pagerrank0 desc,releaseTime desc
通过查看执行计划,没有发现索引查找的图标,说明建立的索引没有起作用。
后来我把两个排序条件减少为一个,SQL语句如下:
SELECT *
   FROM (SELECT ROW_NUMBER() OVER(ORDER BY pagerrank0 desc) AS rownum, 
     *
      FROM View_product  WHERE isPassAudit='true' and pagerRank0>0 ) AS D
    WHERE isPassAudit='true' and pagerRank0>0  AND rownum BETWEEN 47985 AND 48000 ORDER BY pagerrank0 desc
则执行的时间只要150毫秒!
通过查看执行计划发现了索引查找的图标,说明索引确实起作用了。
问题(1) 我确实是对两个字段都建立了索引的,为何有两个排序字段时,索引就无效,而有一个排序字段却有效了呢?
问题(2)我对SQL语句中所需要获取的字段进行了减少,把“*”替换成了“productid,ispassaudit,pagerrank0,releaseTime”则执行的效率也大大提高,只要1秒!,这又是为何?SQL语句如下:
[code=SQL]SELECT *
   FROM (SELECT ROW_NUMBER() OVER(ORDER BY pagerrank0 desc,releasetime desc) AS rownum, 
     productid,ispassaudit,pagerrank0,releaseTime
      FROM View_product  WHERE isPassAudit='true' and pagerRank0>0 ) AS D
    WHERE isPassAudit='true' and pagerRank0>0  AND rownum BETWEEN 47985 AND 48000 ORDER BY pagerrank0 desc,releasetime desc
code]期盼高手能不吝赐教!分不够可以再开帖送上!只求能解决问题

解决方案 »

  1.   

    本人在视图上已经对 pagerrank0和releaseTime建立了非聚集索引,但下面的SQL语句在执行时尽然要18秒左右楼主在那两个字段上加聚集索引看行不??
    CREATE CLUSTERED INDEX IVIEW1 ON 视图名(pagerRank0, releaseTime)
      

  2.   


    一般在记录数较多的时候,select 不用*,而是列出字段名,可以提高效率
      

  3.   

    我对SQL语句中所需要获取的字段进行了减少,把“*”替换成了“productid,ispassaudit,pagerrank0,releaseTime”则执行的效率也大大提高,只要1秒!,这又是为何?
    指定字段本来就比*要快呀
      

  4.   

    感觉select row_number() over...   as rownum,* 有交叉运算的嫌疑.
      

  5.   

    lz,pageranker是做什么用的?
    正好最近也做一些东西,看到参考书也是写全字段的,我就奇怪为什么多此一举写那么累呢,从楼主这找到了答案.
      

  6.   

    用复合索引,指定字段试试先SELECT 指定字段
       FROM (SELECT ROW_NUMBER() OVER(ORDER BY pagerrank0 desc) AS rownum, 
          指定字段    FROM View_product  WHERE isPassAudit='true' and pagerRank0>0 ) AS D
        WHERE isPassAudit='true' 
              and pagerRank0>0 
              AND rownum BETWEEN 47985 AND 48000 
              ORDER BY pagerrank0 desc
      

  7.   

    1:查询优化器有时候并不是走最优化的路径,
    2 :你改成字段名后,数据库引擎不需要去查数据字典,直接就select 字段了
      

  8.   

    CREATE CLUSTERED INDEX IVIEW1 ON 视图名(pagerRank0, releaseTime)这个是聚集的联合索引
      

  9.   

    兄弟我上次有跟你发呀,可能没看吧
    CREATE INDEX
    为给定表或视图创建索引。只有表或视图的所有者才能为表创建索引。表或视图的所有者可以随时创建索引,无论表中是否有数据。可以通过指定限定的数据库名称,为另一个数据库中的表或视图创建索引。语法
    CREATE [ UNIQUE ] [ CLUSTERED | NONCLUSTERED ] INDEX index_name
        ON { table | view } ( column [ ASC | DESC ] [ ,...n ] ) 
    [ WITH < index_option > [ ,...n] ] 
    [ ON filegroup ]< index_option > ::= 
        { PAD_INDEX |
            FILLFACTOR = fillfactor |
            IGNORE_DUP_KEY |
            DROP_EXISTING |
        STATISTICS_NORECOMPUTE |
        SORT_IN_TEMPDB  
    }参数
    UNIQUE为表或视图创建唯一索引(不允许存在索引值相同的两行)。视图上的聚集索引必须是 UNIQUE 索引。在创建索引时,如果数据已存在,Microsoft® SQL Server™ 会检查是否有重复值,并在每次使用 INSERT 或 UPDATE 语句添加数据时进行这种检查。如果存在重复的键值,将取消 CREATE INDEX 语句,并返回错误信息,给出第一个重复值。当创建 UNIQUE 索引时,有多个 NULL 值被看作副本。如果存在唯一索引,那么会产生重复键值的 UPDATE 或 INSERT 语句将回滚,SQL Server 将显示错误信息。即使 UPDATE 或 INSERT 语句更改了许多行但只产生了一个重复值,也会出现这种情况。如果在有唯一索引并且指定了 IGNORE_DUP_KEY 子句情况下输入数据,则只有违反 UNIQUE 索引的行才会失败。在处理 UPDATE 语句时,IGNORE_DUP_KEY 不起作用。SQL Server 不允许为已经包含重复值的列创建唯一索引,无论是否设置了 IGNORE_DUP_KEY。如果尝试这样做,SQL Server 会显示错误信息;重复值必须先删除,才能为这些列创建唯一索引。CLUSTERED创建一个对象,其中行的物理排序与索引排序相同,并且聚集索引的最低一级(叶级)包含实际的数据行。一个表或视图只允许同时有一个聚集索引。具有聚集索引的视图称为索引视图。必须先为视图创建唯一聚集索引,然后才能为该视图定义其它索引。在创建任何非聚集索引之前创建聚集索引。创建聚集索引时重建表上现有的非聚集索引。如果没有指定 CLUSTERED,则创建非聚集索引。说明  因为按照定义,聚集索引的叶级与其数据页相同,所以创建聚集索引时使用 ON filegroup 子句实际上会将表从创建该表时所用的文件移到新的文件组中。在特定的文件组上创建表或索引之前,应确认哪些文件组可用并且有足够的空间供索引使用。文件组的大小必须至少是整个表所需空间的 1.2 倍,这一点很重要。
    NONCLUSTERED创建一个指定表的逻辑排序的对象。对于非聚集索引,行的物理排序独立于索引排序。非聚集索引的叶级包含索引行。每个索引行均包含非聚集键值和一个或多个行定位器(指向包含该值的行)。如果表没有聚集索引,行定位器就是行的磁盘地址。如果表有聚集索引,行定位器就是该行的聚集索引键。每个表最多可以有 249 个非聚集索引(无论这些非聚集索引的创建方式如何:是使用 PRIMARY KEY 和 UNIQUE 约束隐式创建,还是使用 CREATE INDEX 显式创建)。每个索引均可以提供对数据的不同排序次序的访问。对于索引视图,只能为已经定义了聚集索引的视图创建非聚集索引。因此,索引视图中非聚集索引的行定位器一定是行的聚集键。index_name是索引名。索引名在表或视图中必须唯一,但在数据库中不必唯一。索引名必须遵循标识符规则。table包含要创建索引的列的表。可以选择指定数据库和表所有者。view要建立索引的视图的名称。必须使用 SCHEMABINDING 定义视图才能在视图上创建索引。视图定义也必须具有确定性。如果选择列表中的所有表达式、WHERE 和 GROUP BY 子句都具有确定性,则视图也具有确定性。而且,所有键列必须是精确的。只有视图的非键列可能包含浮点表达式(使用 float 数据类型的表达式),而且 float 表达式不能在视图定义的其它任何位置使用。若要在确定性视图中查找列,请使用 COLUMNPROPERTY 函数(IsDeterministic 属性)。该函数的 IsPrecise 属性可用来确定键列是否精确。必须先为视图创建唯一的聚集索引,才能为该视图创建非聚集索引。 在 SQL Server 企业版或开发版中,查询优化器可使用索引视图加快查询的执行速度。要使优化程序考虑将该视图作为替换,并不需要在查询中引用该视图。在创建索引视图或对参与索引视图的表中的行进行操作时,有 7 个 SET 选项必须指派特定的值。SET 选项 ARITHABORT、CONCAT_NULL_YIELDS_NULL、QUOTED_IDENTIFIER、ANSI_NULLS、ANSI_PADDING 和 ANSI_WARNING 必须为 ON。SET 选项 NUMERIC_ROUNDABORT 必须为 OFF。如果与上述设置有所不同,对索引视图所引用的任何表执行的数据修改语句 (INSERT、UPDATE、DELETE) 都将失败,SQL Server 会显示一条错误信息,列出所有违反设置要求的 SET 选项。此外,对于涉及索引视图的 SELECT 语句,如果任何 SET 选项的值不是所需的值,则 SQL Server 在处理该 SELECT 语句时不考虑索引视图替换。在受上述 SET 选项影响的情况中,这将确保查询结果的正确性。如果应用程序使用 DB-Library 连接,则必须为服务器上的所有 7 个 SET 选项指派所需的值。(默认情况下,OLE DB 和 ODBC 连接已经正确设置了除 ARITHABORT 外所有需要的 SET 选项。)如果并非所有上述 SET 选项均有所需的值,则某些操作(例如 BCP、复制或分布式查询)可能无法对参与索引视图的表执行更新。在大多数情况下,将 ARITHABORT 设置为 ON(通过服务器配置选项中的 user options)可以避免这一问题。 强烈建议在服务器的任一数据库中创建计算列上的第一个索引视图或索引后,尽早在服务器范围内将 ARITHABORT 用户选项设置为 ON。有关索引视图注意事项和限制的更多信息,请参见注释部分。column应用索引的列。指定两个或多个列名,可为指定列的组合值创建组合索引。在 table 后的圆括号中列出组合索引中要包括的列(按排序优先级排列)。 说明  由 ntext、text 或 image 数据类型组成的列不能指定为索引列。另外,视图不能包括任何 text、ntext 或 image 列,即使在 CREATE INDEX 语句中没有引用这些列。 
    当两列或多列作为一个单位搜索最好,或者许多查询只引用索引中指定的列时,应使用组合索引。最多可以有 16 个列组合到一个组合索引中。组合索引中的所有列必须在同一个表中。组合索引值允许的最大大小为 900 字节。也就是说,组成组合索引的固定大小列的总长度不得超过 900 字节。有关组合索引中可变类型列的更多信息,请参见注释部分。[ASC | DESC]确定具体某个索引列的升序或降序排序方向。默认设置为 ASC。n表示可以为特定索引指定多个 columns 的占位符。PAD_INDEX指定索引中间级中每个页(节点)上保持开放的空间。PAD_INDEX 选项只有在指定了 FILLFACTOR 时才有用,因为 PAD_INDEX 使用由 FILLFACTOR 所指定的百分比。默认情况下,给定中间级页上的键集,SQL Server 将确保每个索引页上的可用空间至少可以容纳一个索引允许的最大行。如果为 FILLFACTOR 指定的百分比不够大,无法容纳一行,SQL Server 将在内部使用允许的最小值替代该百分比。 你在联机丛书看一下
      

  10.   

    能不工具,怎么还是语法,打开企业管理器,设计表,按CTRL再用鼠标单击要设置的列名(不多选)
    保存即可
      

  11.   

    CREATE  INDEX i xx ON 表(pagerRank0 desc, releaseTime desc)你应该建立降序索引
      

  12.   

    哈哈。建立联合索引后果然有效,我现在知道我上次建立联合索引时为何无效了,上次的查询语句比较复杂,查询如下:SELECT *
       FROM (SELECT ROW_NUMBER() OVER(ORDER BY pagerrank0 DESC, case   when   datediff(day,releaseTime,getdate())=0   then   1   else   0   end   desc,case  when  ISNUMERIC(price)=1 then '3' when price<>'' then '2' else '1' end desc ,releaseTime desc,productid desc) AS rownum, 
         *
          FROM View_product  WHERE isPassAudit='true' and pagerRank0>0 ) AS D
        WHERE isPassAudit='true' and pagerRank0>0  AND rownum BETWEEN 41905 AND 41920 ORDER BY pagerrank0 DESC, case   when   datediff(day,releaseTime,getdate())=0   then   1   else   0   end   desc,case  when  ISNUMERIC(price)=1 then '3' when price<>'' then '2' else '1' end desc ,releaseTime desc,productid desc
    其中排序方式太复杂了。呵呵
      

  13.   

    各位针对我最后的那个SQL还有什么好的提高效率的方法?请指教
      

  14.   

    case   when   datediff(day,releaseTime,getdate())=0   then   1   else   0   end   desc
    这里好像直接就按releaseTime DESC就好了吧
      

  15.   

    因为order by xxx desc..