如果没有TOP 10,使用TOP 10的查询如何比完全相同的查询完成更长的时间?

时间:2011-11-24 13:54:58

标签: sql sql-server sql-server-2008 full-text-search user-defined-functions

我的情况非常简单:

我有一个名为FullTextPagina的表值函数定义如下:

select * from Pagina as p where contains(p.PageText, @term)

然后我有2个查询:

declare @term nvarchar(4000)= N'"DIEGO NUNES J COMBINADO"'

SELECT Id, DtPagina
FROM FullTextPagina(@term)
ORDER BY DtPagina DESC

SELECT TOP 10 Id, DtPagina
FROM FullTextPagina(@term)
ORDER BY DtPagina DESC

除了第二个包含TOP 10语句之外,它们是相同的。并且他们不会返回任何东西。 0行。

第一个立即执行。秒需要1:20米才能完成。

为什么?

PS:

  1. 我已正确设置全文索引
  2. 我在DtPagina
  3. 上有一个非群集的,非唯一的降序索引
  4. 执行计划在此处:http://i.imgur.com/77vJB.png

  5. 修改

    回应@MartinSmith,奇怪的是,表值函数的“执行次数”对于TOP 10案例是118万,对于另一案例是1

    编辑2

    执行计划XML http://tecnologia.novaprolink.com.br/Execution%20plan.xml

    编辑3

    添加选项(重新编译)或取消参数不会影响结果

    SELECT Id, DtPagina
    FROM FullTextPagina(N'"DIEGO NUNES J COMBINADO"')
    ORDER BY DtPagina DESC
    
    SELECT TOP 10 Id, DtPagina
    FROM FullTextPagina(N'"DIEGO NUNES J COMBINADO"')
    ORDER BY DtPagina DESC
    OPTION (RECOMPILE)
    

    编辑4

    FullTextPagina

    的完整代码
    USE [RexConsumo_2011_11]
    GO
    
    /****** Object:  UserDefinedFunction [dbo].[FullTextPagina]    Script Date: 11/24/2011 11:43:09 ******/
    SET ANSI_NULLS ON
    GO
    
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE FUNCTION [dbo].[FullTextPagina] (@term nvarchar(4000))
    RETURNS TABLE 
    AS
    RETURN 
    (
        select * from Pagina as p where contains(p.PageText, @term)
    )
    
    GO
    

1 个答案:

答案 0 :(得分:5)

您遇到的问题是因为SQL Server无法准确估计与谓词匹配的行数。

您的查询正在执行SELECT TOP 10 Id, DtPagina ... ORDER BY DtPagina DESC。关于它如何做到这一点有几个选择

选项1

它可以按顺序扫描DtPagina DESC索引并查看每一行是否与全文谓词匹配,然后在找到索引顺序中的前10个时退出。

选项2

  1. 评估全文谓词
  2. 检索所有匹配行的DtPagina列值
  3. 对它们进行排序并获得前10名。
  4. 当计算第一个选项时,底部计划显示它必须扫描大约600行才能获得10个匹配并且能够退出。这是一个大规模的低估,因为实际上没有行匹配谓词,它需要为整个1,186,533行执行此操作。

    当从顶层计划中计算第二个选项时,可以看出它假定有13846.2个匹配的行将从全文索引查询中返回并需要加入和排序。由于实际数字为零,这是一个很大的估计值。

    因此,这些不正确的估计导致它错误地支持第一个选项。

    我不确定如何提高全文索引统计信息的准确性。也许尝试使用containstable

    重写查询

    编辑:这有点像黑客但可能会有效。如果你尝试

    怎么办?
    declare @term nvarchar(4000)= N'"DIEGO NUNES J COMBINADO"'
    declare @num int = 10
    
    SELECT TOP (@num) Id, DtPagina
    FROM FullTextPagina(@term)
    ORDER BY DtPagina DESC
    

    然后它会假设TOP 100,这可能足以让他们选择其他更有效的计划。