Sql server 2012 在附加条件下使用全文搜索搜索1300万条记录

Sql server 2012 在附加条件下使用全文搜索搜索1300万条记录,sql-server-2012,full-text-search,query-performance,table-valued-parameters,query-tuning,Sql Server 2012,Full Text Search,Query Performance,Table Valued Parameters,Query Tuning,在附加条件下执行SQL Server全文搜索时出现性能问题。(SQL Server 2012) 我试图根据搜索筛选器列表(表值参数)筛选数据,该列表将返回匹配筛选器的所有记录,并且筛选器的单个记录没有表中的任何记录 列SNAME的表Names中已存在全文搜索索引 在存储过程中,表类型参数SearchFilter用于传递名称和地址信息列表 这两个表都有超过1400万条记录,当我们使用过滤器列表中传递的1000条唯一记录执行该过程时,大约需要7分钟才能返回结果(1400条记录) 筛选条件为:包含(名

在附加条件下执行SQL Server全文搜索时出现性能问题。(SQL Server 2012)

我试图根据搜索筛选器列表(表值参数)筛选数据,该列表将返回匹配筛选器的所有记录,并且筛选器的单个记录没有表中的任何记录

SNAME
的表
Names
中已存在全文搜索索引

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

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

筛选条件为:包含(名称)和街道地址、城市、州、邮政编码完全匹配

当SQL Server
包含函数所需的字符串值或变量时,是否有其他方法可以避免while循环

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 

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

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

但是,通过查看您的查询,我发现了一些可能影响性能的其他问题:

  • 插入@result中的
    DISTINCT
    子句。。。选择DISTINCT…
    。它是在
    连接到具有数百万条记录的表的级别上。虽然我知道最终结果可能只包含几千行,但最好将
    DISTINCT
    移到此行:

    SELECT DISTINCT
        UIN, NAME, STREETADDRESS, CITY, STATE, ZIPCODE, PHONE 
    FROM 
        @result 
    
  • 这种条件
    和(ISNULL(ea.STREET1,)+“”+ISNULL(ea.STREET2,)=过滤器\u CTE.StreetAddress
    肯定是不可取的。您可以使用连接和函数(
    ISNULL()
    ),以防止SQL Server在
    dbo.ea
    表上使用现有索引。检查此问题:了解如何以允许使用索引的方式构造
    连接
    /
    WHERE
    条件。 在这种特殊情况下,最好向dbo.Addresses表中添加一个计算列,然后在其上构建一个索引(或将其添加到现有索引中):

  • 因此,修复上面的1。二,。然后在
    右连接中注释
    并包含(en.SNAME,@SearchName)
    条件,并注意执行时间。然后,取消注释
    包含的
    条件,查看添加了多少延迟。这样,您就可以确定是FTS引擎造成了延迟,还是主查询本身需要改进

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


    HTH

    您可以尝试像“%”这样的
    匹配,而不是
    contains()
    ——使用sqlServer进行的优化可能会更快。查询优化在很大程度上取决于所使用的数据和计划/索引-如果您真的必须搜索那么多数据,这将需要一些时间。您确定表
    名称
    地址
    中使用的所有列都有覆盖索引吗,表名称和地址具有右连接筛选器条款中使用的所有列(地址中不包括STREET1和STREET2列)的覆盖索引。如果从
    右连接中删除
    并包含(en.SNAME,@SearchName)
    条件,该怎么办?你试过了吗?会更快吗?谢谢你在我的问题上花费的宝贵时间和精力。我已经更新了while循环中的逻辑,并且还实现了您的一个建议,即使用索引计算列,这提高了存储过程的整体性能。
    CREATE TABLE [dbo].[ADDRESSES]
    (
        ...
        STREET as (ISNULL(ea.STREET1, '') + ' ' + ISNULL(ea.STREET2, '')),
        ...
    )