这里是示例:(表一有约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子句条件下,性能真的很差.另外,如果您查看分析器,则从数据库读取的数量到达屋顶.但是,如果我首先进行全文搜索并将结果放在一个表变量中,并使用该变量,那么所有内容都将超快.读数也低得多.似乎在“糟糕”的情况下,不知何故,它被卡在一个循环,这使得它从数据库中读取很多次,但是当然我不太明白为什么.
现在的问题首先是为什么发生这种情况?问题二就是可扩展的表变量是多少?如果结果是成千上万的记录呢?它还要快吗?
有任何想法吗?
谢谢
解决方法
如果您在查询中的任何位置都包含ContainsTable或ContainsTable,那就是首先被单独执行的部分.意思是即使其余的条件限制您的搜索只有一个记录,既不包含也不包含对此的关注.所以这就像一个并行执行.
现在,由于全文搜索只返回一个密钥字段,它会立即将密钥查找为查询所选的其他索引的第一个字段.所以对于上面的例子,它使用[key],field1,field2查找索引.问题是它根据where子句中的字段为其余的查询选择一个索引.所以对于上面的例子,它会选择我所拥有的包含索引,像field1,field2,id. (表的ID与全文搜索中返回的[Key]相同).所以总结是:
>执行包含状态
>执行查询的其余部分,并根据查询的where子句选择一个索引
它试图合并这两个.因此,如果它为查询的其余部分选择的索引以[key]字段开头,那就行了.但是,如果索引没有[key]字段作为第一个键,它将开始执行循环.它甚至没有进行表扫描,否则通过5000个记录不会那么慢.循环的方式是运行循环,从FTS的结果总数乘以查询的其余部分的总结果数.因此,如果FTS返回2000条记录,其余的查询返回3000,则循环2000 * 3000 = 6,000,000.我不明白为什么.
所以在我的情况下,它执行全文搜索,那么它是否仍然是查询,但是选择了我所基于的field1,id(这是错误的)的覆盖的索引,因此它被拧紧.如果我将覆盖的索引更改为Id,则field1,field2将会非常快.
我的看法是,FTS返回一堆[key],其余的查询返回一堆[Id],然后Id应该与[key]匹配.
当然,我试图在这里简化我的查询,但是实际的查询要复杂得多,我不能只是改变索引.我还有一些场景,其中文本以全文传递是空白的,在这些情况下,我甚至不想加入包含框架.
在这种情况下,将覆盖的索引变为id字段作为第一个字段,将会产生灾难.
无论如何,现在我选择了临时表解决方案,因为它正在为我工作.我也将结果限制为几千,当记录数过高时,这有助于表变量的潜在性能问题.
谢谢