全文索引 - 多个表格的巨大性能下降

时间:2013-06-04 08:00:18

标签: sql-server tsql sql-server-2012 full-text-indexing

我最近一直在学习一些新东西--FULLTEXT索引。

似乎我可以在两个单独的表上运行两个单独的查询(使用CONTAINSTABLE)对两个单独的表获得几乎即时的答案(子10ms)但是当我将两者组合在一起时,查询需要1.3秒 - 或者慢了130倍!!

以下是查询(为此问题而简化)。

查询1:

SELECT
    *
FROM
    dbo.FooBar FB
    INNER JOIN dbo.FooBalls FBS on FB.ID = FBS.ID
    LEFT JOIN CONTAINSTABLE(dbo.FooBar, (Col1, Col2, Col3), @query) FBCONT ON FB.ID = FBCONT.[KEY]
WHERE
    FBCONT.[KEY] IS NOT NULL

查询2:

SELECT
    *
FROM
    dbo.FooBar FB
    INNER JOIN dbo.FooBalls FBS on FB.ID = FBS.ID
    LEFT JOIN CONTAINSTABLE(dbo.FooBalls, (Col1), @query) FBSCONT ON FBS.ID = FBSCONT.[KEY]
WHERE
    FBSCONT.[KEY] IS NOT NULL

查询合并:

SELECT
    *
FROM
    dbo.FooBar FB
    INNER JOIN dbo.FooBalls FBS on FB.ID = FBS.ID
    LEFT JOIN CONTAINSTABLE(dbo.FooBar, (Col1, Col2, Col3), @query) FBCONT ON FB.ID = FBCONT.[KEY]
    LEFT JOIN CONTAINSTABLE(dbo.FooBalls, (Col1), @query) FBSCONT ON FBS.ID = FBSCONT.[KEY]
WHERE
    (FBCONT.[KEY] IS NOT NULL OR FBSCONT.[KEY] IS NOT NULL)

也许我的研究遗漏了一些东西,但有人可以给我一个指标,说明为什么两个条款一起将性能降低了130多倍?

备注:

  • 我已经检查了相关的加入存在的索引 - 通过单个查询的速度进行验证。
  • 这个过程实际上有更多的连接 - 但是它们与查询表完全取消链接,并且在搜索100,000多条记录的结果时,响应时间不到10毫秒。
  • 我尝试用单独的CONTAINS语句替换CONTAINSTABLE - 性能大幅下降,因为我的研究会让我期待。
  • 已设置目录,仅引用要查询的两个表中的四列
  • 目前,@ query参数设置为NVARCHAR(50)。我已经读过使用NVACHAR更快,因为不需要隐式转换。
  • 我知道我可以分别在两个查询上做一个脏的UNION ALL,但我更愿意在可能的情况下编写更好的查询而不是一起破解。另外,如果@query值位于链接到一条记录的单独表中的两列中,UNION ALL会留下可能重复的内容。

任何进一步的建议都将受到极大的欢迎。

1 个答案:

答案 0 :(得分:0)

您的问题评论建议您通过重写查询的无关部分(未在问题中显示)将性能提升到令人满意的水平。

如果它有效,这是公平的,但是当查询的其他不相关部分保持不变时,这并不能解释为什么两个单独的查询和组合查询的差异如此显着。

如果没有查看查询计划和统计结果,很难自信地说出来;但是我可以根据有关如何编写SQL查询的推理来考虑两种可能性:

  1. 在这两个表内部连接后,ID列中的一个或两个(来自FooBarFooBalls)在行集中可能是非唯一的。因此,对CONTAINSTABLE结果集进行两次而不是一次加入可能会导致"育种"比单个连接更多的记录;较大的结果集需要更长的时间才能传递回客户端并显示。 要对此进行测试:比较两个单独查询返回的行计数,并在省略WHERE子句时将这些行计数与每个单独查询的行计数进行比较。较大的行数通常表示查询经过的时间较长(所有其他条件相同)。

  2. 每个单独的查询都使用左外连接编写,但结果集仅限于包含连接成功的行。这实际上是内部联接:SQL Server的查询计划程序可能正在识别此事实并选择执行计划,就像指定了内部联接一样。相反,组合查询需要行 加入(但不一定两者)都成功,这是一个真正的左连接。执行计划可能会对这些连接使用不同的,较慢的方法。 测试一下:查看执行计划,并与请求内部联接而不是左联接的单独查询的执行计划进行比较。