Хранимая процедура SQL Server - «оператор IF» против «где критерии» - PullRequest
4 голосов
/ 27 ноября 2009

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

Proc 1

CREATE PROCEDURE GetEmployeeDetails @EmployeeId uniqueidentifier,
@IncludeDepartmentInfo bit

AS
BEGIN

    SELECT * FROM Employees 
    WHERE Employees.EmployeeId = @EmployeeId

    IF (@IncludeDepartmentInfo = 1)
    BEGIN
        SELECT Departments.* FROM Departments, Employees
        WHERE Departments.DepartmentId = Employees.DepartmentId 
        AND Employees.EmployeeId = @EmployeeId
    END
END

Proc 2

CREATE PROCEDURE GetEmployeeDetails @EmployeeId uniqueidentifier,
 @IncludeDepartmentInfo bit
AS
BEGIN

    SELECT * FROM Employees 
    WHERE Employees.EmployeeId = @EmployeeId

    SELECT Departments.* FROM Departments, Employees
    WHERE Departments.DepartmentId = Employees.DepartmentId 
    AND Employees.EmployeeId = @EmployeeId 
    AND @IncludeDepartmentInfo = 1

END

единственное различие между ними заключается в использовании 'if statment'.

если proc 1 / proc 2 вызывается с чередующимися значениями @IncludeDepartmentInfo, то, по моему пониманию, proc 2 будет работать лучше, потому что он сохранит один и тот же план запроса независимо от значения @IncludeDepartmentInfo, тогда как proc1 изменит план запроса в каждый звонок

ответы действительно оценены

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

Ответы [ 4 ]

2 голосов
/ 27 ноября 2009

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

Если вы повторно используете этот код, другой вызывающий клиент также должен будет знать этот флаг.

Если код делает 2 разные вещи, то почему бы не 2 разных хранимых процесса?

Наконец, гораздо лучше использовать современный синтаксис JOIN и отделить соединение от фильтрации. В этом случае personall y я бы тоже использовал EXISTS.

SELECT
    D.*
FROM
    Departments D
    JOIN
    Employees E ON D.DepartmentId = E.DepartmentId
WHERE  
    E.EmployeeId = @EmployeeId 
    AND
    @IncludeDepartmentInfo = 1
1 голос
/ 27 ноября 2009
SELECT Departments.* FROM Departments, Employees
    WHERE Departments.DepartmentId = Employees.DepartmentId 
    AND Employees.EmployeeId = @EmployeeId 
    AND @IncludeDepartmentInfo = 1

Когда SQL компилирует запрос, подобный этому, он должен быть скомпилирован для любого значения @IncludeDepartmentInfo. Результирующий план вполне может быть тем, который сканирует таблицы и выполняет объединение, а после проверяет переменную, что приводит к ненужному вводу / выводу. Оптимизатор может быть умным и перемещать проверку для переменной впереди фактических операций ввода-вывода в плане выполнения, но это никогда не гарантируется. Вот почему я всегда рекомендую использовать явные IF в T-SQL для запросов, которые должны выполняться по-разному в зависимости от значения переменной (типичным примером являются условия ИЛИ).

Наблюдение gbn также является важным: с точки зрения разработки API лучше иметь согласованный тип возврата (т. Е. Всегда возвращать одинаковую форму и количество наборов результатов).

0 голосов
/ 27 ноября 2009

Разница в производительности была бы слишком мала, чтобы кто-либо мог ее заметить.

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

0 голосов
/ 27 ноября 2009

Когда вы используете оператор if, вы можете выполнить только один запрос вместо двух.Я думаю, что один запрос почти всегда будет быстрее, чем два.Ваше мнение о планах запросов может быть верным, если первый запрос был сложным и занимал много времени, а второй был тривиальным.Однако первый запрос выглядит так, как будто он извлекает одну строку на основе первичного ключа - вероятно, довольно быстро каждый раз.Итак, я бы оставил «если» - но я бы проверил, чтобы проверить.

...