powered by simpleCommunicator - 2.0.60     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Как заставить SQL Server ничего не делать, если переменная NULL
14 сообщений из 14, страница 1 из 1
Как заставить SQL Server ничего не делать, если переменная NULL
    #39670966
VicN
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Доброе утро.

Вот такой запрос:
Код: sql
1.
2.
3.
4.
5.
declare @var int = null

update Detail
set Designation = 'xxx'
where ID = @var



Можно ли заставить SQL Server ничего не делать (не сканировать таблицу или искать индексы), если переменная @var является NULL. Поле ID кластеризованный индекс не допускающий NULL

Знаю что можно так сделать, если поставить внешнее условие IF. Но можно ли в самом запросе такое провернуть? Спрашиваю из любопытства.

Т.е. условно говоря, сервер посмотрел на значение переменной, затем на тип столбца в искомом поле, узнал что поле не допускает NULL и пропускал запрос
...
Рейтинг: 0 / 0
Как заставить SQL Server ничего не делать, если переменная NULL
    #39670976
aleks222
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: sql
1.
where ... and @var is not null



Впрочем, оптимизатор не настолько идиотичен - никакого scan и seek не будет.
...
Рейтинг: 0 / 0
Как заставить SQL Server ничего не делать, если переменная NULL
    #39670977
aleks222
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
План, который тебе нарисовали - это предварительный сферический план в вакууме.
...
Рейтинг: 0 / 0
Как заставить SQL Server ничего не делать, если переменная NULL
    #39670980
iap
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
aleks222
Код: sql
1.
where ... and @var is not null




Впрочем, оптимизатор не настолько идиотичен - никакого scan и seek не будет.
Код: sql
1.
ID=@var

и так означает
Код: sql
1.
@var IS NOT NULL
...
Рейтинг: 0 / 0
Как заставить SQL Server ничего не делать, если переменная NULL
    #39670983
VicN
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
aleks222,
авторВпрочем, оптимизатор не настолько идиотичен - никакого scan и seek не будет.
разве? Я ведь включил действительный план запроса. Выполнил запрос и он показывает такой вот план.

Вообще смущает не только, что сервер делает поиск, но и какое то обновление кластерного индекса. Ведь я индекс совсем не трогаю. Зачем все это?
...
Рейтинг: 0 / 0
Как заставить SQL Server ничего не делать, если переменная NULL
    #39670992
invm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
VicNВообще смущает не только, что сервер делает поиск, но и какое то обновление кластерного индекса. Ведь я индекс совсем не трогаю. Зачем все это?Почитайте что такое кластерный индекс, тогда поймете зачем "какое то обновление кластерного индекса".

По вашим данным можно только сказать, что на таблицу, помимо ПК, наложены еще ограничения.
Если хотите более подробного анализа, покажите полное определение Detail и актуальный план в формате sqlplan.
...
Рейтинг: 0 / 0
Как заставить SQL Server ничего не делать, если переменная NULL
    #39670993
Гавриленко Сергей Алексеевич
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Покажите план в нормальном виде. По фотографиям гадать долго будет.
...
Рейтинг: 0 / 0
Как заставить SQL Server ничего не делать, если переменная NULL
    #39671012
VicN
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Таблица
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
USE [Production]
GO

/****** Object:  Table [dbo].[Detail]    Script Date: 07.07.2018 14:33:18 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[Detail](
	[ID] [int] IDENTITY(1,1) NOT NULL,
	[Designation] [varchar](50) NULL,
	[Name] [varchar](150) NULL,
	[SpecSectionID] [tinyint] NULL,
	[UnitID] [tinyint] NULL,
	[StatusEM] [varchar](50) NULL,
	[DateEM] [datetime] NULL,
	[StatusTD] [varchar](50) NULL,
	[DateTD] [datetime] NULL,
	[FIO] [int] NULL,
	[DateRecord] [datetime] NULL,
	[ClStandProdID] [tinyint] NULL,
	[DocFormatID] [tinyint] NULL,
 CONSTRAINT [pk_Detail] PRIMARY KEY CLUSTERED 
(
	[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
 CONSTRAINT [uq_DesignationName] UNIQUE NONCLUSTERED 
(
	[Designation] ASC,
	[Name] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[Detail] ADD  CONSTRAINT [df_DetailDateRecord]  DEFAULT (sysdatetime()) FOR [DateRecord]
GO

ALTER TABLE [dbo].[Detail]  WITH CHECK ADD  CONSTRAINT [fk_Detail_ClassStandartProduct] FOREIGN KEY([ClStandProdID])
REFERENCES [dbo].[ClassStandartProduct] ([ID])
GO

ALTER TABLE [dbo].[Detail] CHECK CONSTRAINT [fk_Detail_ClassStandartProduct]
GO

ALTER TABLE [dbo].[Detail]  WITH CHECK ADD  CONSTRAINT [fk_Detail_DocumentFormat] FOREIGN KEY([DocFormatID])
REFERENCES [dbo].[DocumentFormat] ([ID])
GO

ALTER TABLE [dbo].[Detail] CHECK CONSTRAINT [fk_Detail_DocumentFormat]
GO

ALTER TABLE [dbo].[Detail]  WITH CHECK ADD  CONSTRAINT [fk_Detail_SpecSection] FOREIGN KEY([SpecSectionID])
REFERENCES [dbo].[SpecificationSection] ([ID])
GO

ALTER TABLE [dbo].[Detail] CHECK CONSTRAINT [fk_Detail_SpecSection]
GO

ALTER TABLE [dbo].[Detail]  WITH CHECK ADD  CONSTRAINT [fk_Detail_Unit] FOREIGN KEY([UnitID])
REFERENCES [dbo].[Unit] ([ID])
GO

ALTER TABLE [dbo].[Detail] CHECK CONSTRAINT [fk_Detail_Unit]
GO

...
Рейтинг: 0 / 0
Как заставить SQL Server ничего не делать, если переменная NULL
    #39671029
invm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
VicN,

Такая форма плана потому, что есть у таблицы фильтрованный индекс ix_Designation, который зависит от столбца Designation.
План отличается от первоначально показанного. Куда дели ограничение, зависящее от Designation?
...
Рейтинг: 0 / 0
Как заставить SQL Server ничего не делать, если переменная NULL
    #39671038
VicN
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
invmVicN,

Такая форма плана потому, что есть у таблицы фильтрованный индекс ix_Designation, который зависит от столбца Designation.
План отличается от первоначально показанного. Куда дели ограничение, зависящее от Designation?
Там было проверочное ограничение check на поля Designation и Name. Удалил, т.к. это ограничение старое и не актуально на данный момент для разрабатываемой мной базы.

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

Видимо так не получится. Тему можно закрывать
...
Рейтинг: 0 / 0
Как заставить SQL Server ничего не делать, если переменная NULL
    #39671039
invm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
VicNПо моему обсуждение пошло в другую сторону.
Изначально я хотел выяснить, есть ли возможность не вынося во внешнее условие IF, сделать проверку переменной на значение NULL и не дергать таблицу и индексы как в плане, если переменная действительно является NULL.По-моему, вы сами поинтересовались почему и зачем такой план.
Если желаете проверять значение переменной, то перепишите условие:
Код: sql
1.
where @var is not null and ID = @var

Тогда в плане, перед доступом к таблице (Clustered Index Seek), появится соответствующий фильтр.
...
Рейтинг: 0 / 0
Как заставить SQL Server ничего не делать, если переменная NULL
    #39671083
Фотография SomewhereSomehow
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
VicN,

Добрый день.

В самом запросе можно «провернуть», как уже выше сказали, добавив дополнительно условие «and @var is not null». Это только для помощи оптимизатору, т.к. логически, в данном случае, это одно и то же. Но дополнительный предикат, дает серверу возможность использовать Startup Filter. Это такой вид фильтра, в котором проверяется некоторое выражение (Startup Expression Predicate) и если оно не выполняется, то вся нижележащая/дочерняя ветка плпнп не будет выполняться.

Добавьте в запросе в условие where «and @var is not null», и посмотрите в свойствах появившегося оператора фильтра Startup Expression Predicate: [@var] IS NOT NULL. Далее сравните в вашем плане и в получившемся свойство Number of Executions оператора Clustered Index Seek, в первом оно 1, т.е. оператор вызывался, во втором 0, т.е. не вызывался.

Хотя на уровне Storage Engine и то, и то не осуществляет доступ к строкам, включите «statistics io», и посмотрите число логических чтений, либо на более поздних версиях, можно посмотреть свойство самого оператора «Actual IO Statistics» и «Number of Rows Read» (которого не будет ни в том, ни в другом случае), можно также посмотреть sys.dm_db_index_operational_stats, чтобы убедиться, что никакого физического доступа нет.

В этом смысле сервер не дурак, так что не переживайте, что: «смущает не только, что сервер делает поиск» - он не делает в данном случае (если только вы не отключите ANSI_NULLS и не сделаете колонку nullable, исключив из РК, если так, то разница в физическом доступе будет, и вы это увидите по всем признакам, перечисленным выше).

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

Далее, по вопросу: «какое то обновление кластерного индекса. Ведь я индекс совсем не трогаю. Зачем все это?»

Операция обновления в SQL Server всегда состоит из двух частей - Read Cursor (не тот, не пользовательский курсор, а внутри сиквела, цикл по строкам), и Write Cursor. Один набирает строки для модификации (например, Clustered Index Seek), другой модифицирует (например, Clustered Index Update). В некоторых простых случаях, сервер, умеет это сворачивать в один оператор:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
use tempdb;
go
create table t(a int primary key);
insert t values (1);
update t set a=1 where a=1;
delete t where a=1;
go
drop table t;


Планы имеют, кроме корневого элемента (INSERT/UPDATE/DELETE), всего по одному оператору плана, который совмещает Write + Read курсоры.

Это работает для самых простых случаев.

И даже для них, можно отключить эту оптимизацию недокументированным флагом 8758.
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
use tempdb;
go
create table t(a int primary key);
dbcc traceon (8758);
go
insert t values (1);
update t set a=1 where a=1;
delete t where a=1;
go
dbcc traceoff (8758);
go
drop table t;


Тогда планы такие, какие должны быть без дополнительной оптимизации.


Вывод из этого такой:
более-менее сложные запросы обновления должны так или иначе содержать в себе часть Read (которая не обязательно получает доступ к строкам, это может быть просто Constant Scan) и часть Write – такова особенность внутренней реализации сиквела.
Так что ваш план содержит Update не потому, что он реально что-то обновляет если NULL, а by design.

Это обусловлено тем, что несмотря на то, сколько строк затрагивает запрос, сервер должен еще корректно отрабатывать блокировки. Попробуйте в двух окнах, в первом:
Код: sql
1.
2.
3.
begin tran;
update Detail with(tablockx) set Designation = 'xxx' where 1=0;
--rollback tran


Во втором:
Код: sql
1.
update Detail set Designation = 'xxx' where 1=0


Несмотря на то, что оба запроса не затрагивают никаких строк по условию 1=0, все равно второй будет заблокирован и будет ждать, пока вы не закончите транзакцию первого. А т.к. итераторы выполнения (не только update, но и все остальные) должны корректно работать с блокировками, логика запроса не единственное, что обуславливает их физический дизайн.

Подытоживая,
- В данном примере лишнего физического доступа не будет, если он реально не нужен.
- Форма плана и наличие тех или иных оператор обусловлена особенностями физической реализации, которые должны учитывать много других аспектов работы, кроме логической составляющей запроса.
...
Рейтинг: 0 / 0
Как заставить SQL Server ничего не делать, если переменная NULL
    #39671106
VicN
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SomewhereSomehow,

Спасибо за развернутый ответ, буду по немного разбираться и обдумывать.

Остальным также спасибо за участие в обсуждении
...
Рейтинг: 0 / 0
Как заставить SQL Server ничего не делать, если переменная NULL
    #39671116
Владислав Колосов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
По-моему ни один такой трюк не пройдет, если включена принудительная параметризация. Это надо иметь в виду.
...
Рейтинг: 0 / 0
14 сообщений из 14, страница 1 из 1
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Как заставить SQL Server ничего не делать, если переменная NULL
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]