SQL - Оптимизация сложных поисковых запросов - PullRequest
2 голосов
/ 15 июня 2010

В настоящее время я разрабатываю хранимую процедуру для сложного поиска в большой базе данных. Поскольку существует много тысяч записей, которые могут быть возвращены, я хочу использовать подкачку страниц. Хотя это работает, я думаю, что это слишком медленно. Я прочитал много постов и статей, касающихся разбивки запросов SQL и оптимизации производительности. Но большинство «оптимизаций» были полезны только для самых простых запросов, таких как «дать пункты 20-30 из таблицы х».

Поскольку наш мир не так прост и есть более сложные запросы, я хотел бы получить некоторую помощь в оптимизации следующего запроса:

CREATE PROCEDURE [SearchItems]
@SAttr1 BIT = 0,
@SAttr2 BIT = 0,
@SAttr3 BIT = 0,
@Flag1 BIT = 0,
@Flag2 BIT = 0,
@Param1 VARCHAR(20),
@Param2 VARCHAR(10),
@SkipCount BIGINT,
@TakeCount BIGINT,
@SearchStrings NVARCHAR(1000)    
AS
    DECLARE @SearchStringsT TABLE(
        Val NVARCHAR(30)
    )

    INSERT INTO @SearchStringsT 
    SELECT * FROM dbo.Split(@SearchStrings,',');

WITH ResultTable AS (
    SELECT  Table1.*, ROW_NUMBER() OVER(ORDER BY Table1.ID ASC) AS [!ROWNUM!]
    FROM Table1
    INNER JOIN Table2 ON Table1.ID = Table2.FK1
    INNER JOIN Table3 ON Table2.ID = Table3.FK2
    INNER JOIN Table4 ON Table3.XX = Table4.FKX
    WHERE Table1.X1 = @Parameter1
    AND
        (@Flag1 = 0 OR Table1.X2 = 1) AND
        (@Flag2 = 0 OR Table2.X4 = @Parameter2) AND
        (@Flag3 = 0 OR EXISTS(SELECT * FROM Table5 WHERE Table5.ID = Table3.X1)) 
    AND
    (                   
        (@SAttr1 = 0 OR EXISTS(SELECT * FROM @SearchStringsT WHERE Table1.X1 LIKE Val)) OR
        (@SAttr2 = 0 OR EXISTS(SELECT * FROM @SearchStringsT WHERE Table2.X1 LIKE Val)) OR
        (@SAttr3 = 0 OR EXISTS(SELECT * FROM @SearchStringsT WHERE Table3.X1 LIKE Val)) OR
        (@SAttr4 = 0 OR EXISTS(SELECT * FROM @SearchStringsT WHERE Table4.X1 LIKE Val))
    )
)
SELECT TOP(@TakeCount) * FROM ResultTable
WHERE [!ROWNUM!] BETWEEN (@SkipCount + 1) AND (@SkipCount + @TakeCount)
RETURN

Параметры @SAttr являются битовыми параметрами, определяющими, выполнять поиск в поле или нет, параметры @Flag включают / выключают проверку некоторых логических выражений, @SkipCount и @TakeCount используются для подкачки страниц. @SearchString - это список поисковых слов, разделенных запятыми, уже включающий подстановочные знаки.

Я надеюсь, что кто-то может помочь мне оптимизировать это, потому что один поиск в базе данных с 20 000 записей в основной таблице длится 800 мс и увеличивается с увеличением количества записей. Окончательная заявка должна иметь дело с более чем 100 000 записей.

Большое спасибо за любую помощь. Marks

Ответы [ 2 ]

2 голосов
/ 15 июня 2010

Хотя я и согласен с Томом Х., что в этом случае лучше всего использовать динамический SQL (а я - девушка из числа хранящихся процессов, поэтому я не говорю это очень часто), возможно, вы нена ваших таблицах нет хорошей индексации.Все возможные поля поиска проиндексированы?Все ли FK проиндексированы?

Я имею в виду, что 20 000 - это крошечная и крошечная таблица, а 100 000 - тоже, так что действительно может показаться, что вы еще не проиндексированы.

Проверьте план выполнения напосмотреть, если индексы используются.

1 голос
/ 15 июня 2010

Хранимые процедуры не очень хороши для того, чтобы быть универсальными, потому что они не позволяют SQL Server всегда использовать оптимальные методы.В похожей ситуации недавно я использовал ( gasp ) динамический SQL.Мои хранимые процедуры поиска построят код SQL для выполнения поиска, используя нумерацию страниц, как у вас (WITH с ROW_NUMBER () и т. Д.).Преимущество было в том, что если параметры указывали, что одна часть информации не использовалась в поиске, то сгенерированный код пропустил бы ее.В конце концов это позволило улучшить планы запросов.

Убедитесь, что вы правильно используете sp_executesql для предотвращения атак с использованием SQL-инъекций.

...