你先执行没有Top的,再执行有Top的,测试一下时间

解决方案 »

  1.   

    查询1:他们速度是一样的,之所以显示第二个快,是因为第一个执行了,以经存储在SQL缓存中了,所以第二个执行快,你可以查询1 执行多次就知道了。
    查询问:加了top限制,就少扫描了165949-1000条数据,当然比第二条语句快(第二条没加TOP限制,是全表扫描)
      

  2.   

    查询1:他们速度是一样的,之所以显示第二个快,是因为第一个语句执行后,所有数据以经存储在SQL缓存中了,
    第二个语句执行时就不需要任何I/O操作了,当然快了,你可以查询1 执行多次就知道了。
    查询2:第一个语句加了top限制,就只扫描表前1000条数据,当然比第二条语句快(第二条没加TOP限制,是全表扫描)
      

  3.   

    我按照上面说的反过来
    DECLARE @d datetime
    SET @d = getdate()SELECT * FROM product WHERE CONTAINS(name,'男上装') OR CONTAINS(text,'男上装')
    SELECT datediff(ms,@d,getdate())
    SET @d = getdate()
    SELECT top 1000 * FROM product WHERE CONTAINS(name,'男上装') OR CONTAINS(text,'男上装')
    SELECT datediff(ms,@d,getdate())先取得所有的。。再取得TOP1000的。
    结果:(总数:14条)
    14条数据用时313(这是没用top 1000后)
    14条数据用时3780(这是用了top 1000后)
    同时。“查询1”和“查询2”是“一样”的查询语句。只是条件不同。
    查询1查出的总数是14条,查询2查出的总数是165949条。当总数14条时。用了TOP 1000 比没用TOP 1000的查询花费时间多。
    当总数165949条时,用了TOP 1000 比没用TOP 1000的查询花费时间少。
      

  4.   

    数据量大时,你为什么还用top 1000 改为  top 比结果更大的数 如 top 200000 比较一下
      

  5.   

    我只需要根据条件取里面的前1000条出来。
    可是当数据少时,如14条。取TOP 1000 比没TOP 1000的要慢很多。
    而数据多时,如160K。取TOP 1000 比没TOP 1000的要快很多。。
      

  6.   

    楼主的查询使用了 OR 条件, 这个查询大致上会这样生成这样的执行计划:
    1. 执行两句:
    SELECT top 1000 * FROM product WHERE CONTAINS(name,'男上装') 
    SELECT top 1000 * FROM product WHERE CONTAINS(text,'男上装')
    2. 对结果做一个join这样就涉及取两表join联接的算法了
    有top 的情况下, 一般使用的是嵌套循环, 没有top的情况下, 多半使用的是哈希联接嵌套循环使用的搜索方法是: 
    将一个联接输入用作外部输入表(显示为图形执行计划中的顶端输入),将另一个联接输入用作内部(底端)输入表。外部循环逐行处理外部输入表。内部循环会针对每个外部行执行,在内部输入表中搜索匹配行。很显然, 如果匹配的数据很少的话(准确地说匹配的数据在扫描顺序的尾部, 匹配的数据越少, 发生这种情况的可能性越高), 那么扫描势必会遍历完整个表, 这样的效率显然不高.
    而哈希联接不存在这种问题所以你会发觉, 匹配的数据量少的情况下, TOP 的执行效率反而低.
      

  7.   

    你把有TOP 的语句改为:SELECT top 1000 * FROM product WHERE CONTAINS(name,'男上装') OR CONTAINS(text,'男上装')
    OPTION(HASH JOIN)应该会发现, 是否加TOP的效率都差不多了(注意, 如果匹配的数据量多的话, 要考虑不加TOP时, 取回大量数据对查询时间的影响)
      

  8.   

    邹老大好。看了你的解释。我明白了一些。
    根据你的意见:
    我改成:
    DECLARE @d datetime
    SET @d = getdate()
    SELECT top 1000 * FROM product WHERE CONTAINS(name,'男上装') OR CONTAINS(text,'男上装')
    OPTION(HASH JOIN)
    SELECT datediff(ms,@d,getdate())SQL查询分析器显示为:
    服务器: 消息 8622,级别 16,状态 1,行 3
    由于此查询中定义的提示,查询处理器未能生成查询计划。请重新提交查询,并且不要在查询中指定任何提示,也不要使用 SET FORCEPLAN。
      

  9.   

    不行的。我就执行:
    SELECT top 1000 * FROM product WHERE CONTAINS(name,'男上装') OR CONTAINS(text,'男上装')
    OPTION(HASH JOIN)显示错误为:
    服务器: 消息 8622,级别 16,状态 1,行 1
    由于此查询中定义的提示,查询处理器未能生成查询计划。请重新提交查询,并且不要在查询中指定任何提示,也不要使用 SET FORCEPLAN。
      

  10.   

    如果不加OPTION(HASH JOIN)就可以正确执行。
      

  11.   

    怪事了, 我查了2000的联机帮助, 2000也支持option的子句啊.OPTION 子句
    指定应在整个查询中使用所指定的查询提示。每个查询提示只能指定一次,但允许指定多个查询提示。用该语句只可能指定一个 OPTION 子句。查询提示影响语句中的所有运算符。如果主查询中涉及 UNION,则只有涉及 UNION 运算符的最后一个查询可以有 OPTION 子句。如果一个或多个查询提示导致查询优化器不生成有效计划,则产生 8622 错误。注意  由于查询优化器通常为查询选择最优执行计划,所以建议只把 <join_hint>, <query_hint> 和 <table_hint> 作为经验丰富的数据库管理员的最终手段。
    语法
    [ OPTION ( < query_hint > [ ,...n ] ) ] < query_hint > ::= 
        {    { HASH | ORDER } GROUP 
        | { CONCAT | HASH | MERGE } UNION 
        | { LOOP | MERGE | HASH } JOIN 
        | FAST number_rows 
        | FORCE ORDER 
        | MAXDOP number 
        | ROBUST PLAN 
        | KEEP PLAN 
        | KEEPFIXED PLAN
        | EXPAND VIEWS 
        } 
      

  12.   

    我也看了帮助。2000里也有。
    上网搜索了下资料。给的HASH JOIN的例子是:SELECT A.PONO,B.VCODE,B.VNAME FROM TBLPO A INNER JOIN TBLVENDOR B ON A.VENDORID=B.ID OPTION (HASH JOIN)我刚刚试了OPTION(HASH UNION),可以运行。但是结果和没加OPTION(HASH UNION)时所用的时间。一样。
      

  13.   

    我应该搞错了, 你那个是or的, 是内部优化的时候使用了联接, 所以无法使用 option(hash join)
    (2005应该在这方面改进了, 所以我在2005下倒是成功的)
    你直接看查询计划好了, 看看它使用的联接是否如我猜测的那样.
      

  14.   

    我想也是这样的。。我的想法是:因为我的是TOP 1000,当取得数据少时,如只有14条,他就将一直读至最尾。
    如果数据多时。当到达1000时。他就不再读了执行计划里:
    TOP 1000 少数据时:是Nested Loops/Left Semi Jion而*少数据,*多数据,TOP1000多数据时:是Merge Join/Left Semi Join
    但是不知道怎么优化。。
      

  15.   

    用TOP的话是显示有多少条记录,刚看到的。
      

  16.   

    个人经历:通常这种情况都和索引和key值有关。
      

  17.   

    Try:查询1:
    DECLARE @d datetime
    SET @d = getdate()
    set rowcount 1000
    SELECT * FROM product WHERE CONTAINS(name,'男上装') OR CONTAINS(text,'男上装')
    SELECT datediff(ms,@d,getdate())
    SET @d = getdate()
    set rowcount 0
    SELECT * FROM product WHERE CONTAINS(name,'男上装') OR CONTAINS(text,'男上装')
    SELECT datediff(ms,@d,getdate())
      

  18.   

    top 确实影响执行计划,曾经见一个sql,top 63 和top 64 采取的执行计划完全不同
      

  19.   

    对不起。今天搬家。下午才可以上网。。Haiwer(海阔天空) 的方法:
    DECLARE @d datetime
    SET @d = getdate()
    set rowcount 1000
    SELECT * FROM product WHERE CONTAINS(name,'男上装') OR CONTAINS(text,'男上装')
    SELECT datediff(ms,@d,getdate())
    SET @d = getdate()
    set rowcount 0
    SELECT * FROM product WHERE CONTAINS(name,'男上装') OR CONTAINS(text,'男上装')
    SELECT datediff(ms,@d,getdate())效率是:
    6356
    283感觉使用set rowcount 1000和用top 1000一样的。
      

  20.   

    我觉得,没必要用OPTION指定连接选项,因为你写语句的时候,并不知道能查询出多少记录,而且发生效率差别的是在返回不多记录的情况,这种情况一个查询所用的时间本来就不多,如果你考虑你的语句需要长期使用的话(比如写到应用程序里),你可以只需考虑返回超过1000行的情况。