Why are the performances of these 2 queries so different?

前端 未结 3 2164
清酒与你
清酒与你 2021-02-20 03:41

I have a stored proc that searches for products (250,000 rows) using a full text index.

The stored proc takes a parameter that is the full text search condition. This pa

相关标签:
3条回答
  • 2021-02-20 04:19

    OR can crush performance, so do it this way:

    DECLARE @Filter VARCHAR(100)
    SET @Filter = 'FORMSOF(INFLECTIONAL, robe)'
    
    IF @Filter IS NOT NULL
    BEGIN
        SELECT TOP 100 ID FROM dbo.Products
        WHERE CONTAINS(Name, @Filter)
    END
    ELSE
    BEGIN
        SELECT TOP 100 ID FROM dbo.Products
    END
    

    Look at this article: Dynamic Search Conditions in T-SQL by Erland Sommarskog and this question: SQL Server 2008 - Conditional Query.

    0 讨论(0)
  • 2021-02-20 04:19

    You've introduced an OR condition. In most cases it is simply much faster to check explicitly for NULL and perform one query vs your method.

    For instance try this:

    IF @Filter IS NULL
     BEGIN
    SELECT TOP 100 ID FROM dbo.Products
    END
    ELSE
    BEGIN
    SELECT TOP 100 ID FROM dbo.Products
    WHERE @Filter CONTAINS(Name, @Filter)
    END
    
    0 讨论(0)
  • 2021-02-20 04:20

    The first query plan looks straightforward:

    1. a full text search to resolve CONTAINS(Name, @Filter)
    2. an index scan to look up the other columns of the matched rows
    3. combine the two using a hash join

    The concatenation operator forms a union of two recordsets. So it looks like the second query is doing:

    1. an index scan (later used to look up other columns)
    2. a constant scan. I assume it's treating your query as not parameterized, so the query plan doesn't have to work for any other value of @Filter. If correct, the constant scan resolves @Filter is not null.
    3. a full text search to resolve CONTAINS(Name, @Filter)
    4. unions the result of 3 with the empty set from 2
    5. loop joins the result of 1 and 4 to look up the other columns

    A hash join trades memory for speed; if your system has enough memory, it's much faster than a loop join. This can easily explan a 10-100x slowdown.

    One fix is to use two distinct queries:

    if @Filter is null
        SELECT TOP 100 ID FROM dbo.Products
    else
        SELECT TOP 100 ID FROM dbo.Products WHERE CONTAINS(Name, @Filter)
    
    0 讨论(0)
提交回复
热议问题