3

我正在尝试寻找解决方案以改进字符串搜索过程,因此我选择了全文索引策略。

但是,在实现它之后,我仍然可以看到,在使用多个带有 OR 子句的全文索引表使用多个字符串进行搜索时,性能会受到影响。

(例WHERE CONTAINS(F.*,'%Gayan%') OR CONTAINS(P.FirstName,'%John%')

作为一种解决方案,我正在尝试使用CONTAINSTABLE期望性能改进。

现在,我在CONTAINSTABLE使用LEFT JOIN

请看下面的例子。

查询 1

SELECT F.Name,p.*
        FROM P.Role PR
INNER JOIN P.Building F ON PR.PID = F.PID
LEFT JOIN CONTAINSTABLE(P.Building,*,'%John%') AS FFTIndex ON F.ID = FFTIndex.[Key]
LEFT JOIN P.Relationship PRSHIP ON PR.id = prship.ToRoleID
LEFT JOIN P.Role PR2 ON PRSHIP.ToRoleID = PR2.ID
LEFT JOIN P.Person p ON pr2.ID = p.PID
LEFT JOIN CONTAINSTABLE(P.Person,FirstName,'%John%') AS PFTIndex ON P.ID = PFTIndex.[Key]
WHERE F.Name IS NOT NULL

这会产生以下结果。

查询 1 输出

查询 2

SELECT F.Name,p.*
FROM P.Role PR
INNER JOIN P.Building F ON PR.PID = F.PID
INNER JOIN P.Relationship PRSHIP ON PR.id = prship.ToRoleID
INNER JOIN P.Role PR2 ON PRSHIP.ToRoleID = PR2.ID
INNER JOIN P.Person p ON pr2.ID = p.PID
WHERE CONTAINS(F.*,'%Gayan%') OR CONTAINS(P.FirstName,'%John%') 
AND F.Name IS NOT NULL

结果

查询 2 输出

期望以作为 SQL SERVEROR子句行为的方式使用查询 1。据我所知CONTAINSTABLE,查询 1 将数据与building表连接起来,其余结果将被忽略,以便表CONTAINSTABLEPerson获取已经包含从building表中过滤的关键字的数据。

如果keyword = Building,我想匹配两个表中的关键字,而不管在两个表中搜索保存的记录。在每个表中都有一条记录就足够了。

概括

查询 2 执行良好,但在索引中的单词增长时会产生缓慢。查询 1 似乎已优化(当涉及多个在线资源和 MS 文档时),但是,它并没有给我预期的输出。

有没有办法解决这个问题?

我并不严格依附于CONTAINSTABLE. 建议另一种优化方法也很重要。 谢谢你。

4

1 回答 1

1

如果没有完整的数据集,很难明确地说出,但有几个可供探索的选项

删除无效的 % 通配符

你为什么用'%SearchTerm%'?如果您使用不带通配符 (%) 的搜索词,性能会提高吗?如果您想要一个与前缀匹配的单词,请尝试类似 WHERE CONTAINS (String,'"SearchTerm*"')

试试临时表

我的猜测是 CONTAINS 比 CONTAINSTABLE 略快,因为它不计算排名,但我不知道是否有人尝试过对其进行基准测试。无论哪种方式,在加入其余表之前,我都会尝试将匹配项保存到临时表中。这将允许优化器创建更好的执行计划

SELECT ID INTO #Temp 
FROM YourTable 
WHERE CONTAINS (String,'"SearchTerm"')

SELECT *
FROM #Temp
INNER JOIN...

通过去除嘈杂的词优化全文索引

你可能会发现你有一些嘈杂的词,也就是在你的数据中重复出现很多次的词,这些词没有意义,比如“the”或者一些商业术语。将这些添加到您的停止列表将意味着您的全文索引将忽略它们,从而使您的索引更小从而更快

下面的查询将在顶部列出最常见的索引词

Select *
From sys.dm_fts_index_keywords(Db_Id(),Object_Id('dbo.YourTable') /*Replace with your table name*/)
Order By document_count Desc

这个或那个标准

对于您WHERE CONTAINS(F.*,'%Gayan%') OR CONTAINS(P.FirstName,'%John%')想要这个或那个的标准,这很棘手。即使在使用简单的相等运算符时,OR 子句通常也会执行。我会尝试做两个查询并合并结果,例如:

SELECT * FROM Table1 F
/*Other joins and stuff*/
WHERE CONTAINS(F.*,'%Gayan%')
UNION
SELECT * FROM Table2 P 
/*Other joins and stuff*/
WHERE CONTAINS(P.FirstName,'%John%') 

或者这是更多的工作,但您可以将所有数据加载到包含所有列的巨型非规范化表中。然后将全文索引应用于该表并以这种方式调整您的搜索条件。这可能是最快的搜索方法,但是您必须确保数据在非规范化表和基础规范化表之间同步

SELECT B.*,P.* INTO DenormalizedTable
FROM Building AS B
INNER JOIN People AS P

CREATE FULL TEXT INDEX ft ON DenormalizedTable
etc...
于 2022-02-23T20:46:57.817 回答