Too many parameter values slowing down query

2019-09-17 11:10发布

问题:

I have a query that runs fairly fast under normal circumstances. But it is running very slow (at least 20 minutes in SSMS) due to how many values are in the filter.

Here's the generic version of it, and you can see that one part is filtering by over 8,000 values, making it run slow.

SELECT DISTINCT 
    column 
FROM 
    table_a a 
JOIN 
    table_b b ON (a.KEY = b.KEY)
WHERE 
    a.date BETWEEN @Start and @End
    AND b.ID IN (... over 8,000 values)
    AND b.place IN ( ... 20 values)
ORDER BY 
    a.column ASC

It's to the point where it's too slow to use in the production application.

Does anyone know how to fix this, or optimize the query?

回答1:

To make a query fast, you need indexes. You need a separate index for the following columns: a.KEY, b.KEY, a.date, b.ID, b.place. As gotqn wrote before, if you put your 8000 items to a temp table, and inner join it, it will make the query even faster too, but without the index on the other part of the join it will be slow even then.



回答2:

What you need is to put the filtering values in temporary table. Then use the table to apply filtering using INNER JOIN instead of WHERE IN. For example:

IF OBJECT_ID('tempdb..#FilterDataSource') IS NOT NULL
BEGIN;
    DROP TABLE #FilterDataSource;
END;

CREATE TABLE #FilterDataSource
(
    [ID] INT PRIMARY KEY
);

INSERT INTO #FilterDataSource ([ID])
-- you need to split values

SELECT DISTINCT column 
FROM table_a a 
INNER JOIN table_b b 
    ON (a.KEY = b.KEY)
INNER JOIN #FilterDataSource FS
    ON b.id = FS.ID
WHERE a.date BETWEEN @Start and @End
    AND b.place IN ( ... 20 values)
ORDER BY .column ASC;

Few important notes:

  • we are using temporary table in order to allow parallel execution plans to be used
  • if you have fast (for example CLR function) for spiting, you can join the function itself
  • it is not good to use IN with many values, the SQL Server is not able to build always the execution plan which may lead to time outs/internal error - you can find more information here