Избегайте таких хранимых процедур, если это возможно. Если вам не нужен этот параметр, даже не используйте выражение WHERE
. Это тривиально, чтобы сделать сгенерированные ORM запросы - просто не добавляйте вызов .Where()
. Это лучшее решение.
Такие универсальные запросы приводят к снижению производительности. Вы не получаете никакой дополнительной производительности, используя хранимую процедуру. Любое повышение производительности происходит потому, что сервер может повторно использовать планы выполнения, созданные для предыдущих запросов (не хранимых процедур), независимо от того, находятся ли они в хранимых процедурах или нет.
Тем не менее, при запросе «ловить все» этот план выполнения может быть неправильным - план, сгенерированный, когда параметр пуст, будет сканировать всю таблицу, не используя индексы. Этот план будет использоваться повторно, даже если вы передадите значение в последующем вызове. С другой стороны, план, сгенерированный, когда параметр имеет значение, может использовать индекс, даже если он не нужен.
Один из способов исправить это - добавить WITH RECOMPILE. к хранимой процедуре:
CREATE PROCEDURE [dbo].[Values_Select]
@VisionId NVARCHAR(50) = NULL
WITH RECOMPILE
AS
BEGIN
SELECT Id,
...
FROM dbo.viw1
WHERE VisionID = @VisionId OR @VisionId IS NULL
END
Сервер будет генерировать новый план выполнения для всех запросов в хранимой процедуре при каждом запуске. Таким образом, вы теряете любые выгоды от кэширования плана выполнения.
Другой вариант - использовать RECOMPILE
в качестве подсказки запроса. Это позволяет перекомпилировать только те операторы, которые в этом нуждаются:
CREATE PROCEDURE [dbo].[Values_Select]
@VisionId NVARCHAR(50) = NULL
AS
BEGIN
SELECT Id,
...
FROM dbo.viw1
WHERE VisionID = @VisionId OR @VisionId IS NULL WITH OPTION(RECOMPILE)
END
Другая возможность - сгенерировать параметризованных dynamici c SQL, добавляя предложение WHERE
только при необходимости. Хотя намного проще и безопаснее позволить ORM сделать это:
CREATE PROCEDURE [dbo].[Values_Select]
@VisionId NVARCHAR(50) = NULL
AS
BEGIN
DECLARE @sSQL NVARCHAR(2000), @Where NVARCHAR(1000) = ''
SET @sSQL = 'SELECT Id,.... FROM dbo.view1 ' -- Notice the trailing space
IF @VisionId is not null
SET @Where = @Where + 'AND VisionId= @_VisionId ' -- Trailing space here too
-- Other optional parameters
IF LEN(@Where) > 0
SET @sSQL = @sSQL + 'WHERE ' + RIGHT(@Where, LEN(@Where)-3)
EXEC sp_executesql @sSQL,
N'@_VisionId nvarchar(50), ...', -- parameter names
@_VisionId = @VisionId, ... -- parameter values