代码之家  ›  专栏  ›  技术社区  ›  Eric P

FreeText查询很慢-包括TOP和Order By

  •  4
  • Eric P  · 技术社区  · 14 年前

    SELECT TOP 1 ID, Name FROM Product WHERE contains(Name, '"White Dress"') ORDER BY DateMadeNew desc

    运行大约需要1分钟。DateMadeNew上有一个非聚集索引,Name上有FreeText索引。

    这是执行计划的链接。 http://screencast.com/t/ZDczMzg5N

    看起来FullTextMatch执行了超过40万次。为什么会这样?怎样才能更快?

    更新日期:5/3/2010

    Optimizer估计有28K条记录与“White Dress”匹配,而实际上只有1条。 http://screencast.com/t/NjM3ZjE4NjAt

    似乎优化器只使用短语中的第一个单词来搜索基数。

    6 回复  |  直到 14 年前
        1
  •  1
  •   Martin Smith    14 年前

    编辑

    http://technet.microsoft.com/en-us/library/cc721269.aspx#_Toc202506240

    为选择了正确的联接类型 全文查询。基数 这对正确的计划非常重要。 所以首先要检查的是 FulltextMatch基数估计。 这是估计的命中数 在索引中进行全文搜索 字符串。例如,在 术语词。在大多数情况下,它应该 非常准确,但是如果 走了很长一段路,你可以 单一条款通常很好, 但是估计多个术语,例如 短语或查询更为复杂 索引中项的交集 将基于 估计是好的,计划是坏的 可能是查询引起的 优化器成本模型。唯一的办法 解决计划问题的方法是使用查询 或优化。

    因此,它根本无法从存储的信息中知道这两个搜索词可能是完全独立的,还是共同发现的。也许你应该有两个独立的程序一个是单字查询,你可以让乐观主义者做它的事情,另一个是多字程序,你强制一个“足够好”的计划(sys.dm\u fts\u index\u keywords可能会有帮助,如果你不想一个一刀切的计划)。

    注意:您的单字过程可能需要使用WITHRECOMPILE选项查看本文的这一部分。

    不过,你的新计划看起来还是很糟糕。看起来它只从全文查询部分返回1行,但扫描Product表中的所有770159行。

    它的性能如何?

    CREATE TABLE #tempResults
    (
    ID int primary key,
    Name varchar(200),
    DateMadeNew datetime
    )
    
    INSERT INTO #tempResults
    SELECT 
          ID, Name, DateMadeNew 
          FROM Product 
          WHERE contains(Name, '"White Dress"')
    
    
    SELECT TOP 1
        *
        FROM #tempResults
        ORDER BY DateMadeNew desc
    
        2
  •  2
  •   Quassnoi    14 年前

    看起来FullTextMatch执行了超过40万次。为什么会这样?

    TOP 1

    怎样才能更快?

    如果更新统计信息没有帮助,请尝试向查询中添加提示:

    SELECT  TOP 1 *
    FROM    product pt
    WHERE   CONTAINS(name, '"test1"')
    ORDER BY
            datemadenew DESC
    OPTION (HASH JOIN)
    

    这将迫使发动机使用 HASH JOIN 连接表和全文查询输出的算法。

    全文查询被视为一个远程源,返回由 KEY INDEX 提供于 FULLTEXT INDEX

    更新:

    ORM 使用参数化查询,可以创建计划指南。

    • 发送 逐字
    • SSMS 使用提示并将其另存为 XML
    • 使用 sp_create_plan_guide OPTION USE PLAN 要强制优化器始终使用此计划。
        3
  •  1
  •   KM.    14 年前

    我看不到相关的执行计划,网络警察正在封锁,所以这只是猜测。。。

    TOP ORDER BY

    SELECT TOP 1
        *
        FROM (SELECT 
                  ID, Name, DateMadeNew 
                  FROM Product 
                  WHERE contains(Name, '"White Dress"')
             ) dt
        ORDER BY DateMadeNew desc
    
        4
  •  1
  •   ronalchn Damien    12 年前

    ID article_number .

    查询:

    select top 50 id, article_number, name, ... 
    from ARTICLE 
    CONTAINS(*,'"BLACK*" AND "WHITE*"')
    ORDER BY ARTICLE_NUMBER
    

    如果全文索引连接到 身份证件 如果全文索引连接到 ARTICLE_NUMBER UNIQUE 那时候总是很快。

        5
  •  1
  •   Community kfsone    7 年前

    1. 选项(HASH JOIN)-不好,因为可能会出错 “由于此查询中定义的提示,查询处理器无法生成查询计划。在不指定任何提示和不使用SET FORCEPLAN的情况下重新提交查询。“

    2. 从(原始\选择)排序依据中选择前1*…-不好,当您需要使用分页结果时,请从您的原始目录中选择

    3. sp\u create\u plan\u guide-不好,因为要使用plan\u guide,您必须为特定的sql语句保存计划,这对动态sql语句(如ORM生成的语句)不起作用

    二。我的解决方案包含两部分 1.用于全文搜索的自联接表 2.使用MS SQL哈希连接提示 MSDN Join Hints

    SELECT TOP 1 ID, Name FROM Product WHERE contains(Name, '"White Dress"') 
    ORDER BY DateMadeNew desc
    

    SELECT TOP 1 p.ID, p.Name FROM Product p INNER HASH JOIN Product fts ON fts.ID = p.ID
    WHERE contains(fts.Name, '"White Dress"') 
    ORDER BY p.DateMadeNew desc
    

    如果您使用的是NHibernate,有/没有Castle活动记录,我已经回复了 post 如何编写拦截器来修改查询,将内部连接替换为内部哈希连接

        6
  •  0
  •   Paul McLoughlin    14 年前

    关于这一点有几点想法:

    2) 您使用的是什么版本的SQL Server?我在SQLServer2008中遇到了一个类似的问题,结果只不过是没有安装ServicePack1。安装SP1后,一个FreeText查询花了几分钟时间(由于实际执行的次数太多)变成了一秒钟。