1

使用其他條件執行SQL Server全文搜索時出現性能問題。 (SQL Server 2012)使用具有附加條件的全文搜索來搜索1300萬條記錄

我想根據搜索過濾器列表(表值參數)過​​濾數據,它將返回匹配過濾器的所有記錄,並且過濾器的單個記錄沒有表中的任何記錄。

對於列SNAME,全文搜索索引已經在表Names上。

在存儲過程中,表類型參數SearchFilter用於傳遞名稱和地址信息列表。

這兩個表都有超過1400萬條記錄,當我們在過濾器列表中傳遞1000個唯一記錄並執行該過程時,大約需要7分鐘才能返回結果(1400條記錄)。

過濾標準是:包含(名稱)和streetaddress,城市,州,郵編完全匹配。

是否有任何替代避免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 
+1

你可以嘗試'喜歡 '%%''的比賽,而不是'包含()' - 這_might_更快depoending由SQLSERVER做了優化。查詢優化高度依賴於使用的數據和計劃cerated/indexes y - 如果您真的必須搜索那麼多的數據,它將需要一些時間。 –

+0

你確定表名字和地址是否覆蓋了你的'RIGHT JOIN Filter_CTE'子句中使用的所有列的索引? – andrews

+0

是的,表名稱和地址具有覆蓋您的RIGHT JOIN Filter_CTE子句 –

回答

0

目前,它是不可能在CONTAINSCONTAINSTABLE使用列名作爲搜索條件。因此,在應用了FTS謂詞的數據表和SearchFilter表之間不能執行直接JOIN

當前在其他問題/論壇中找到的解決方案是循環訪問過濾器列表並在搜索條件的變量中輸入CONTAINS,就像您一樣。所以,你不會擺脫這個循環。

然而,看着你的查詢我看到了一些可能會影響性能的其他問題:在INSERT INTO @result ... SELECT DISTINCT ...

  1. 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肯定不是優化搜索。您使用連接和函數(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然後在RIGHT JOIN中註釋AND CONTAINS(en.SNAME,@SearchName)條件並注意執行時間。之後,取消註釋CONTAINS的條件並查看添加了多少延遲。通過這種方式,您肯定會知道FTS引擎是否因延遲而受到責備,或者您的主查詢本身需要改進。

爲了能夠提供更多建議,我們需要查看您的過程的執行計劃。您可以使用此頁面共享您的查詢執行計劃:https://www.brentozar.com/pastetheplan/

HTH

+0

感謝您花費在我的問題上的寶貴時間和努力。 我已經更新了while循環中的邏輯,並且還實現了您的計算列索引的建議之一,並且它改進了存儲過程的整體性能。 –

+0

@ K.Engineer太棒了!我很高興能夠提供幫助。我希望你至少有15個代表能夠投我的答案,呵呵:)。 – andrews