请提供更多答案... - 在 SQL 中执行此文本搜索的最有效方法是什么?

More answers please... - What is the most efficient way of doing this text search in SQL?

它的丑陋是出于必要,但它仍然需要 运行 在适当的时候,我将展示我尝试实现它的两种方法。我相信递归 CTE 最终会解决它,但我在实施它时遇到了一些严重的困难。

基本上,我在 db1 中有一个名为 dis_det 的 table,其中有 3 个重要字段:dis_iddis_typedis_q_val. dis_q_val 是要搜索特定术语和短语的文本字段。

搜索条件位于 db2 中的 table 中,名为 tag_keywords,还有 3 个相关字段:tag_idkeyword_idkeyword_namekeyword_name 是要搜索的文本列表,tag_id 是带有标记信息的 table 的外键。

我的最终要求是 DISTINCT dis_id, tag_id 的列表。我已经知道我不能只 FREETEXT 整个事情,因为我每个关键字得到 7-25,000 个结果,而使用 LIKE '%' + keyword_name + '%' returns 最多大约 1500 个结果。这不是一个巨大的测试集(大约 180,000 个披露记录,<1000 个关键字),但是 LIKE 版本 运行 在查询大约 17 小时后内存不足,这对于处理来说太长了。另一方面,使用 FREETEXT,大约 20 分钟后 运行 内存不足。我可以获得更多内存,但我需要及时获得准确的结果。

所以我的主要问题是 "Will a recursive CTE fix this?",如果是,"How do I implement it?"。我还想在 keyword_name 中集成对多个单词的检查,这样我就可以对多个单词使用 LIKE,对单个单词值使用 FREETEXT

现在输入一些代码:

--query using FREETEXT
DECLARE @i INT = 1, @keyword NVARCHAR(65)
DECLARE @results TABLE(dis_id BIGINT, tag_id INT)
WHILE @i < 909
BEGIN
    SET @keyword = (SELECT keyword_name FROM db2..tag_keywords WHERE keyword_id = @i)
    INSERT INTO @results
    SELECT DISTINCT dis_id
        , (SELECT tag_id FROM db2..tag_keywords WHERE keyword_id = @i)
    FROM db1..dis_det
    WHERE dis_type = 'reg' AND FREETEXT(dis_val, @keyword)
    SET @i = @i + 1
END
--runs for about 45 minutes and runs out of memory with way too many results

.

--query using LIKE
DECLARE @i INT = 1, @keyword NVARCHAR(65)
DECLARE @results TABLE(dis_id BIGINT, tag_id INT)
WHILE @i < 909
BEGIN
    SET @keyword = (SELECT keyword_name FROM db2..tag_keywords WHERE keyword_id = @i)
    INSERT INTO @results
    SELECT DISTINCT dis_id
        , (SELECT tag_id FROM db2..tag_keywords WHERE keyword_id = @i)
    FROM db1..dis_det
    WHERE dis_type = 'reg' AND dis_val LIKE '%' + @keyword + '%'
    SET @i = @i + 1
END
--runs for about 17 hours and runs out of memory

我真的不知道如何操纵递归 CTE 的示例来使它们与此一起工作。如果您有可行的实现,我将不胜感激。

据我所知,递归 CTE 的锚点应该如下所示:

SELECT d.dis_id
    , (SELECT tag_id FROM db2..tag_keywords WHERE tag_keyword_id = @j) AS tag_id
    , 1 AS @j
FROM db1..dis_det AS d
WHERE d.dis_type = 'reg' AND
    (d.dis_q_val LIKE '%' + (SELECT keyword_name FROM db2.tag_keywords WHERE tag_keyword_id = @j) + '%'
    AND (SELECT CHARINDEX(' ',(SELECT keyword_name FROM db2.tag_keywords WHERE tag_keyword_id = @j))) > 0
    ) OR (FREETEXT(d.dis_q_val, (SELECT keyword_name FROM db2.tag_keywords WHERE tag_keyword_id = @j))
    AND (SELECT CHARINDEX(' ',(SELECT keyword_name FROM db2.tag_keywords WHERE tag_keyword_id = @j))) = 0
    )

但是该查询给出了错误,我不确定如何将 @j 递增写入其中。

再次感谢,抱歉花了这么长时间 post 更多信息。

/*
 * -- Latest edit, still looking for a better solution: 02/27/2016 --
 */

我仍在寻找比我的自我回答更快 运行 的解决方案,它只是上述代码的工作集合。根据 FREETEXT INDEX 的状态,它 运行 在 8 到 14 小时之间。在大多数情况下,这种事情几乎是无法接受的table。我希望递归或合并技术能更有效地应对这种情况,但我不确定如何实施。

再次感谢。

在有人提出更好的建议之前,我已经为我的低效解决方案提出了上述理想的混合:

DECLARE @i INT = 1, @tag_id INT, @keyword NVARCHAR(65)
DECLARE @results TABLE(dis_id BIGINT, tag_id INT)
WHILE @i < 909
BEGIN
    SET @tag_id = (SELECT tag_id FROM db2..tag_keywords WHERE keyword_id = @i)
    SET @keyword = (SELECT keyword_name FROM db2..tag_keywords WHERE keyword_id = @i)
    IF(CHARINDEX(@keyword, ' ') >= 0)
    BEGIN
        INSERT INTO @results
        SELECT DISTINCT dis_id, @tag_id
        FROM db1..dis_det
        WHERE dis_type = 'reg' AND dis_value LIKE '%' + @keyword + '%'
    END

    IF(CHARINDEX(@keyword, ' ') <0)
    BEGIN
        INSERT INTO @results
        SELECT DISTINCT dis_id, @tag_id
        FROM db1..dis_det
        WHERE dis_type = 'reg' AND FREETEXT(dis_value, @keyword)
    END
    PRINT 'Iteration number: ' + CAST(@i AS NVARCHAR(3)) --to mark progress while watching it run
    SET @i = @i + 1
END
SELECT * FROM @results
ORDER BY dis_id, tag_id

运行大约 8.5 小时。对于可能 运行 每月一次的事情来说显然不是最佳选择,但我相信城里的大人物可以为周末类型的交易设置它。

这将是公认的答案,直到有人想出更快的 运行 时间。

感谢您的浏览。

如评论中所述,我发布了关于简单加入 table 来执行查询的想法。

DECLARE @i INT = 1, @max INT = (SELECT MAX(tag_keyword_id) FROM db2..tag_keywords)
DECLARE @results TABLE(dis_id BIGINT, tag_id INT)
WHILE @i <= @max
BEGIN
    SELECT DISTINCT details.dis_id, keyword.tag_id 
    FROM db2..tag_keywords keyword 
    JOIN db1..dis_det details 
        ON details.dis_type='reg' AND details.dis_q_val like '%' + keyword.keyword_name + '%' 
    GROUP BY details.dis_id, keyword.tag_id
    PRINT 'Iteration number: ' + CAST(@i AS NVARCHAR(5)) + 'of: ' + CAST(@max AS NVARCHAR(5))
    SET @i = @i + 1
END
SELECT * FROM @results
ORDER BY dis_id, tag_id

另一个出现在我脑海中的想法是某种预处理,我实际上不时这样做。就像将新关键字添加到 db2 时一样,关键字 table 上的某些触发器会 运行 查询并将结果以所需格式存储在某些 table 中,以便您稍后查询需要。这当然取决于条件,但是如果 db1 增长很快并且添加的关键字不那么频繁,它可能会带来显着的性能提升。