我正在使用sql 2008全文搜索,我遇到严重的性能问题,具体取决于我如何使用Contains或ContainsTable。
以下是示例:(表一有大约5000条记录,table1上有一个覆盖索引,其中包含where子句中的所有字段。我试图简化语句,如果存在语法问题,请原谅我。)
情景1:
select * from table1 as t1
where t1.field1=90
and t1.field2='something'
and Exists(select top 1 * from containstable(table1,*, 'something') as t2
where t2.[key]=t1.id)
结果:10秒(非常慢)
情景2:
select * from table1 as t1
join containstable(table1,*, 'something') as t2 on t2.[key] = t1.id
where t1.field1=90
and t1.field2='something'
结果:10秒(非常慢)
场景3:
Declare @tbl Table(id uniqueidentifier primary key)
insert into @tbl select {key] from containstable(table1,*, 'something')
select * from table1 as t1
where t1.field1=90
and t1.field2='something'
and Exists(select id from @tbl as tbl where id=req1.id)
结果:一分之一秒(超快)
从底线看,如果我在任何类型的连接中使用Containstable或者select语句的where子句条件也有其他条件,那么性能真的很糟糕。此外,如果您查看分析器,数据库中的读取次数将进入顶层。但是,如果我首先进行全文搜索并将结果放入表变量并使用该变量,那么一切都会超快。读数也低得多。它似乎在“糟糕”的情况下,不知何故它陷入循环,导致它从数据库中读取多次,但当然我不明白为什么。
现在问题首先是为什么会发生这种情况?问题二是表变量如何可扩展?如果它产生了成千上万的记录呢?它仍然会很快。
有什么想法吗? 感谢
答案 0 :(得分:12)
我在这个问题上花了很长时间,基于运行很多场景,这就是我想到的:
如果您在查询中的任何位置包含Contains或ContainsTable,那么这是首先执行而非独立执行的部分。这意味着,即使其余条件将您的搜索限制为仅一个记录,也不包含也不包含对此的关注。所以这就像一个并行执行。
现在,由于全文搜索仅返回Key字段,因此它会立即查找Key作为为查询选择的其他索引的第一个字段。因此,对于上面的示例,它使用[key],field1,field2查找索引。问题是它根据where子句中的字段为其余查询选择索引。所以对于上面的例子,它选择我所拥有的覆盖索引,类似于field1,field2,Id。 (表的Id与全文搜索返回的[Key]相同)。总结如下:
所以在我的情况下,它进行全文搜索,然后它完成了查询的其余部分,但是选择了我所拥有的覆盖索引,该索引基于field1,field2,id(这是错误的),结果是螺丝起来。如果我将覆盖的索引更改为Id,field1,field2,一切都会非常快。
我的期望是FTS返回一堆[key],其余的查询返回一堆[Id],然后Id应与[key]匹配。
当然,我试图在这里简化我的查询,但实际的查询要复杂得多,我不能只改变索引。我也有确实以全文传递的文本为空白的场景,在这些场景中我甚至不想加入containsstable。 在那些情况下,将我的覆盖索引更改为将id字段作为第一个字段,将产生灾难。
无论如何,现在我选择了临时表解决方案,因为它对我有用。我还将结果限制为几千,这有助于在记录数量过高时表变量的潜在性能问题。
感谢
答案 1 :(得分:7)
通常它的工作速度非常快:
select t1.*, t2.Rank
from containstable(table1, field2, 'something') as t2
join table1 as t1 ON t1.id = t2.Key AND t1.field1=90
order by t2.Rank desc
在您放置搜索条件时存在很大差异:在JOIN或WHERE中。
答案 2 :(得分:4)
我将在这里猜测你的问题与我链接的其他线程相同。您是否发现问题出现在多个单词搜索词中?
如果是这样,我的答案就会适用。
来自http://technet.microsoft.com/en-us/library/cc721269.aspx#_Toc202506240
最重要的是 选择了正确的连接类型 全文查询。基数 对FulltextMatch STVF的估计 对于正确的计划非常重要。 所以首先要检查的是 FulltextMatch基数估计。 这是估计的点击次数 在全文搜索的索引中 串。例如,在查询中 图3这应该接近了 包含的文件数量 术语'字'。在大多数情况下它应该 非常准确,但如果估计 很久以前,你可以 产生糟糕的计划。估计 单一术语通常非常好, 但估计多个术语,如 短语或AND查询更复杂 因为不可能知道什么 索引中的术语交集 将根据频率而定 索引中的术语。如果基数 估计是好的,一个糟糕的计划 可能是由查询引起的 优化器成本模型。唯一的方法 修复计划问题是使用查询 提示强制某种加入 或OPTIMIZE FOR。
因此,根据它存储的信息,它根本无法知道这两个搜索项是否可能是完全独立的,或者通常是一起找到的。也许你应该有2个独立的程序,一个用于单词查询,你可以让优化器执行它的东西,一个用于多字搜索术语,你强制一个“足够好”的计划(sys.dm_fts_index_keywords可能有帮助,如果你想做一个粗略估计基数本身)。
如果您遇到单字查询问题,可以应用链接文章中的这段话。
在SQL Server 2008全文搜索中,我们可以更改计划 基于所使用的搜索项的基数估计生成。如果查询计划是固定的(因为它位于存储过程内的参数化查询中),则此步骤可以 没有发生。因此,即使此计划不适合给定的搜索词,编译后的计划也始终提供此查询。
因此您可能需要使用RECOMPILE选项。