使用全文搜索和其他条件搜索1300万条记录

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用全文搜索和其他条件搜索1300万条记录相关的知识,希望对你有一定的参考价值。

使用其他条件执行SQL Server全文搜索时的性能问题。 (SQL Server 2012)

我试图根据搜索过滤器列表(表值参数)过​​滤数据,这将返回匹配过滤器的所有记录,过滤器的单个记录没有来自表的任何记录。

对于Names列,全文搜索索引已经在表SNAME上。

在存储过程中,表类型参数SearchFilter用于传递名称和地址信息列表。

两个表都有超过1400万条记录,当我们执行过程时,过滤器列表中传递了1000条唯一记录,大约需要7分钟才能返回结果(1400条记录)。

过滤条件是:包含(名称)和streetaddress,city,state,zip完全匹配。

有什么替代方法可以避免while循环,因为SQL Server CONTAINS函数需要字符串值或变量吗?

CREATE TABLE [dbo].[Names]
(
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [UIN] [varchar](9) NULL,
    [SNAME] [varchar](500) NULL,
    CONSTRAINT [PK_Names] 
        PRIMARY KEY CLUSTERED ([ID] ASC)
)

CREATE TABLE [dbo].[ADDRESSES]
(
    [UIN] [varchar](9) NULL,
    [STREET1] [varchar](100) NULL,
    [STREET2] [varchar](50) NULL,
    [CITY] [varchar](30) NULL,
    [STATE] [varchar](2) NULL,
    [ZIP] [varchar](10) NULL    
) ON [PRIMARY]

CREATE TYPE [dbo].[SearchFilter] AS TABLE
(
    [UIN] [varchar](40) NULL,
    [SNAME] [varchar](max) NULL,
    [StreetAddress] [varchar](max) NULL,
    [City] [varchar](max) NULL,
    [State] [varchar](50) NULL,
    [Zip] [varchar](20) NULL
)

-- Stored procedure logic
DECLARE @filterList AS [dbo].[SearchFilter]

DECLARE @NoOfRows INT, @counter INT = 0

SET @NoOfRows = (SELECT COUNT(1) FROM @filterList)

DECLARE @result TABLE (UIN varchar(40), 
                       NAME varchar(500), 
                       StreetAddress varchar(1000), 
                       Zipcode varchar(20),
                       State varchar(20),
                       City varchar(1000),
                       IsRecordFound varchar(50)
                      );

WHILE (@NoOfRows > @counter)
BEGIN
    DECLARE @SearchName VARCHAR(4000)

    SET @SearchName = (SELECT '"'+SNAME+'"' FROM @filterList ORDER BY SNAME OFFSET @counter ROWS FETCH NEXT 1 ROWS ONLY)  

    --Start: Process to Select Records
    ;WITH Filter_CTE AS
    (
        SELECT 
            SNAME, StreetAddress, City, State, ZipCode 
        FROM
            @filterList 
        ORDER BY 
            SNAME 
            OFFSET @counter ROWS FETCH NEXT 1 ROWS ONLY 
    )
    INSERT INTO @result (UIN, NAME, STREETADDRESS, CITY, STATE, ZIPCODE, PHONE, IsRecordFound)
        SELECT DISTINCT 
            en.UIN, ISNULL(en.SNAME, Filter_CTE.SNAME),
            Filter_CTE.StreetAddress, Filter_CTE.ZipCode,
            Filter_CTE.state, Filter_CTE.City,
            IIF(en.UIN IS NULL, 'Not Found', 'Found') AS IsRecordFound 
        FROM 
            dbo.Names en 
        INNER JOIN 
            dbo.ADDRESSES ea ON en.UIN = ea.UIN
        RIGHT JOIN 
            Filter_CTE ON ea.ZIP = Filter_CTE.Zip 
                       AND ea.STATE = Filter_CTE.State 
                       AND ea.CITY = Filter_CTE.City 
                       AND (ISNULL(ea.STREET1, '') + ' ' + ISNULL(ea.STREET2, '')) = Filter_CTE.StreetAddress
                       AND CONTAINS(en.SNAME,@SearchName)
            --END

    SET @counter += 1
END 

SELECT 
    UIN, NAME, STREETADDRESS, CITY, STATE, ZIPCODE, PHONE 
FROM 
    @result 
答案

目前,无法在CONTAINSCONTAINSTABLE中使用列名作为搜索条件。因此,您不能在数据表和JOIN表之间使用FTS谓词直接执行SearchFilter

在其他问题/论坛中找到的当前解决方案是遍历过滤器列表并在变量中使用搜索条件提供CONTAINS,就像您一样。所以,你不会摆脱这个循环。

但是,查看您的查询时,我发现了许多可能影响性能的其他问题:

  1. DISTINCT中的INSERT INTO @result ... SELECT DISTINCT ...条款。它在JOIN到具有数百万条记录的表格的水平上。虽然我知道最终结果可能只包含几千行,但最好将DISTINCT移到此行: SELECT DISTINCT UIN, NAME, STREETADDRESS, CITY, STATE, ZIPCODE, PHONE FROM @result
  2. 这种情况AND (ISNULL(ea.STREET1, '') + ' ' + ISNULL(ea.STREET2, '')) = Filter_CTE.StreetAddress肯定不是SARGable。您使用串联和函数(ISNULL())来阻止SQL Server在dbo.ADDRESSES ea表上使用现有索引。检查这个问题:What makes a SQL statement sargable?,看看如何以允许使用索引的方式构造JOIN / WHERE条件。在这种特殊情况下,最好将计算列添加到dbo.Addresses表,然后在其上构建索引(或将其添加到现有索引): CREATE TABLE [dbo].[ADDRESSES] ( ... STREET as (ISNULL(ea.STREET1, '') + ' ' + ISNULL(ea.STREET2, '')), ... )

所以修正上面的1.和2.然后在AND CONTAINS(en.SNAME,@SearchName)中注释RIGHT JOIN条件并注意执行时间。然后,取消注释CONTAINS条件,看看增加了多少延迟。通过这种方式,您可以确定是否因为延迟或主要查询本身需要改进而归咎于FTS引擎。

为了能够提供更多建议,我们需要查看您的程序的执行计划。您可以使用此页面共享您的查询执行计划:https://www.brentozar.com/pastetheplan/

HTH

以上是关于使用全文搜索和其他条件搜索1300万条记录的主要内容,如果未能解决你的问题,请参考以下文章

全文搜索与空间查询

实体框架、代码优先和全文搜索

SQL Server 全文搜索返回意外结果

使用 Postgres 全文搜索搜索完全匹配的最佳方法是啥?

自2008 R2以来,是否有任何Sql Server全文搜索(FTS)性能改进?

全文搜索用于提取文本片段(返回预期文本及其周围)