Стоимость использования OPTION (RECOMPILE) против присоединения к таблицам - PullRequest
0 голосов
/ 12 декабря 2018

Использование: SQL Server 2016 +

Я хотел посмотреть, есть ли способ оценить, сколько времени потребуется SQL Server для перекомпиляции плана выполнения запроса.У нас есть несколько хранимых процедур, в которых мы выбираем из таблицы 1 на основе обнуляемого параметра в таблице 2. Например, если клиент не равен NULL, вернуть его продажи, иначе вернуть все продажи.

Пример данных:

DROP TABLE IF EXISTS dbo.TestTable1;
DROP TABLE IF EXISTS dbo.TestTable2;

CREATE TABLE dbo.TestTable1 (ID INT NOT NULL PRIMARY KEY CLUSTERED , TextValue NVARCHAR(255) NULL);
CREATE TABLE dbo.TestTable2 (ID INT NOT NULL PRIMARY KEY CLUSTERED , TextValue NVARCHAR(255) NULL);

INSERT INTO TestTable1 (ID, TextValue)
VALUES (1, N'Table 1 - Text 1'),
       (2, N'Table 1 - Text 2'),
       (3, N'Table 1 - Text 3'),
       (4, N'Table 1 - Text 4'),
       (5, N'Table 1 - Text 5'),
       (6, N'Table 1 - Text 6'),
       (7, N'Table 1 - Text 7'),
       (8, N'Table 1 - Text 8'),
       (9, N'Table 1 - Text 9'),
       (10, N'Table 1 - Text 10');

INSERT INTO TestTable2 (ID, TextValue)
VALUES (1, N'Table 2 - Text 1'),
       (2, N'Table 2 - Text 2'),
       (3, N'Table 2 - Text 3'),
       (4, N'Table 2 - Text 4'),
       (5, N'Table 2 - Text 5'),
       (6, N'Table 2 - Text 6'),
       (7, N'Table 2 - Text 7'),
       (8, N'Table 2 - Text 8'),
       (9, N'Table 2 - Text 9'),
       (10, N'Table 2 - Text 10');

Это значительно упрощено, поскольку у нас было бы несколько возможных условий, связанных с несколькими таблицами.В настоящее время мы рассматриваем перекомпиляцию запроса, чтобы соединения со вторичной таблицей выполнялись только при необходимости.

DECLARE @LookupValue NVARCHAR(50);

SET @LookupValue = NULL;

SELECT  *
  FROM  dbo.TestTable1 T1
 WHERE  @LookupValue IS NULL
    OR  EXISTS ( SELECT TOP (1) 1 A FROM dbo.TestTable2 T2 WHERE T1.ID = T2.ID AND T2.TextValue = @LookupValue)
OPTION (RECOMPILE)

SET @LookupValue = N'Table 2 - Text 1';

SELECT  *
  FROM  dbo.TestTable1 T1
 WHERE  @LookupValue IS NULL
    OR  EXISTS ( SELECT TOP (1) 1 A FROM dbo.TestTable2 T2 WHERE T1.ID = T2.ID AND T2.TextValue = @LookupValue)
OPTION (RECOMPILE);

Как видно из приведенного ниже плана запроса, таблица перекомпиляции 2 эффективно удаляется из выполнения.

Execution Plan

Однако перекомпиляция требует определенных затрат, и я собираюсь отследить эти накладные расходы, чтобы принять разумные решения относительно того, какой из наших запросов отформатировать таким образом.В общем, я вижу, что перекомпиляция происходит последовательно быстрее, но есть много сообщений о том, что это означает, что планы выполнения могут оказаться намного менее оптимальными.

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

Большое спасибо.

Ответы [ 2 ]

0 голосов
/ 28 апреля 2019

Чтобы получить представление о времени компиляции, просмотрите:

https://ericblinn.com/quantifying-compile-time

В основном, используйте SET STATISTICS TIME ON перед запросом, чтобы получать сообщения консоли о времени, потраченном вКомпиляция и выполнение.

Как примечание, не ваш вопрос, беспокойство по поводу времени компиляции может быть не самым продуктивным способом действий.Довольно низкоуровневые и непредсказуемые вещи, ИМХО.

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

Принудительное выполнение повторного анализа и пересоздания планов при одновременном обращении к непрерывным транзакциям может не бытьНаиболее разумный выбор.

Кроме того, проверьте следующий блог:

https://blogs.msdn.microsoft.com/robinlester/2016/08/10/improving-query-performance-with-option-recompile-constant-folding-and-avoiding-parameter-sniffing-issues/

В нем есть некоторые сведения об OPTION (OPTIMIZE FOR (@string = '')), которыеможет быть полезным.

Но, как уже было сказано выше, из этого я делаю вывод не об использовании перекомпиляции, а о разработке процедур доступа к данным, которые по возможности избегают этого.

0 голосов
/ 28 апреля 2019

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

Declare @customerid int
Set @customerid = (select customerid from dbo.table2)

If @customerid is null
BEGIN
Select datadesired from table1
END

ELSE
BEGIN
Select datadesired from table1
INNER JOIN table2 ON PKey = FKey
WHERE customerid = @customerID
END

Это должно работать фантастически, если вы хотите извлечь все данные или определенный набор данных.Если вы пойдете сложнее, как вы и предполагали, возможно, динамический SQL - это, вероятно, лучший вариант.Вы все еще можете использовать этот метод для создания запроса для каждого сценария?Конечно, если хочешь.Но я могу в значительной степени гарантировать, что если вы попытаетесь использовать логику ветвления where для создания двух совершенно разных запросов, а затем передадите им сколько-нибудь значительный объем данных, у вас будут проблемы, но выполнение двух отдельных запросов работает так же, как если бы оба этих запросажили в разных хранимых процедурах, и вы выяснили, какую процедуру вызывать на веб-уровне (также возможно).

...