使用 CONTAINS 进行全文搜索非常慢

Full text search with CONTAINS is very slow

我们尝试在 Azure 数据库上使用全文搜索,但在使用 CONTAINS 搜索时遇到了性能问题。

我们的数据采用星型模式,事实 table 启用了聚集列存储索引,大约有 4000 万行。下面是我们如何在维度上使用 CONTAINS 并在不同查询上对 Fact table 进行聚合:

使用 EXISTS 查询 1:

SELECT f.[FK_DimCompanyCodeId], SUM(f.NetValueInUSD)
FROM [SPENDBY].[FactInvoiceDetail] f

WHERE EXISTS (
        SELECT * FROM [SPENDBY].[DimCompanyCode] d

        WHERE f.[FK_DimCompanyCodeId] = d.Id
        AND CONTAINS(d.*, 'Comcast'))

GROUP BY f.[FK_DimCompanyCodeId]

ORDER BY SUM(f.NetValueInUSD) DESC

此查询似乎 运行 永远不会 return 结果。

外键FK_DimCompanyCodeId]上有非聚集索引,搜索时只有一行returned Comcast:

SELECT id  FROM [SPENDBY].[DimCompanyCode] d
WHERE CONTAINS(d.*, 'Comcast');
-- will return id = 5

并且有大约 2700 万行事实 table 其中有 FK_DimCompanyCodeId = 5.

使用 INNER JOIN 的查询 2:

SELECT f.[FK_DimCompanyCodeId], SUM(f.NetValueInUSD)
FROM [SPENDBY].[FactInvoiceDetail] f

INNER JOIN [SPENDBY].[DimCompanyCode] d ON (f.[FK_DimCompanyCodeId] = d.Id)
WHERE CONTAINS(d.*, 'Comcast')

GROUP BY f.[FK_DimCompanyCodeId]
ORDER BY SUM(f.NetValueInUSD) DESC

这个查询似乎 运行 永远不会 return 结果也是如此。

查询 3 使用#temp table:

SELECT id INTO #temp FROM [SPENDBY].[DimCompanyCode] d
WHERE CONTAINS(d.*, 'Comcast');

SELECT f.[FK_DimCompanyCodeId], SUM(f.NetValueInUSD)
FROM [SPENDBY].[FactInvoiceDetail] f

WHERE EXISTS (
        SELECT * FROM #temp
        WHERE f.[FK_DimCompanyCodeId] = #temp.Id)

GROUP BY f.[FK_DimCompanyCodeId]

ORDER BY SUM(f.NetValueInUSD) DESC

很快,return5秒后出结果。

为什么案例 1 和案例 2 的全文搜索速度如此之慢。

问题是竞争索引——一个用于 JOIN,一个用于过滤器。也许子查询会说服 SQL 服务器首先使用文本索引:

SELECT f.[FK_DimCompanyCodeId], SUM(f.NetValueInUSD)
FROM [SPENDBY].[FactInvoiceDetail] f JOIN
     (SELECT id
      FROM [SPENDBY].[DimCompanyCode] cc
      WHERE CONTAINS(cc.*, 'Comcast')
     ) cc
     ON cc.id = f.FK_DimCompanyCodeId
GROUP BY f.[FK_DimCompanyCodeId]
ORDER BY SUM(f.NetValueInUSD) DESC

如果您在 FactInvoiceDetail(FK_DimCompanyCodeId) 上有一个索引,它可能也会有所帮助。

最终,我发现 CONTAINS 在特定列上效果很好(例如 Description):

SELECT f.[FK_DimCompanyCodeId], SUM(f.NetValueInUSD)
FROM [SPENDBY].[FactInvoiceDetail] f
WHERE  f.[FK_DimCompanyCodeId] IN  (
        SELECT d.Id FROM [SPENDBY].[DimCompanyCode] d
        WHERE CONTAINS(d.[Description], 'Comcast')
)
GROUP BY f.[FK_DimCompanyCodeId]
ORDER BY SUM(f.NetValueInUSD) DESC

为了搜索整个table,CONTAINSTABLE会有最好的性能,避免使用#temp table:

SELECT f.[FK_DimCompanyCodeId], SUM(f.NetValueInUSD)
FROM [SPENDBY].[FactInvoiceDetail] f
LEFT OUTER JOIN CONTAINSTABLE([SPENDBY].[DimCompanyCode], *, '"Comcast"') ct 
ON f.[FK_DimCompanyCodeId] = ct.[Key]
WHERE ct.[Key] IS NOT NULL
GROUP BY f.[FK_DimCompanyCodeId]
ORDER BY SUM(f.NetValueInUSD) DESC