Разместить здесь вашу рекламу


Не удаляйте временные таблицы, умоляю

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Мне часто приходится видеть чужой код на T-SQL. Я уже привык видеть в конце процедур привычное

drop table #a
drop table #b

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

Но недавно я стал встречать совершенно жуткий антипаттерн. Не знаю, откуда он распространился.

Встречайте:

  if object_id('tempdb..#mytemp') is not null
    DROP TABLE #mytemp
  create table #mytemp (...)

Мне обидно, что SQL server считают идиотом со стекающими от вырождения слюнями, идиотом, неспособным заботиться о контексте выполнения. Но важнее то, что это код - потенциальная бомба с часовым механизмом.

Покажем это на примере. Создадим внешнюю процедуру:

create procedure ALPHA
as
  create table #mytemp (n int, ALPHA varchar(128))
  insert into #mytemp select 1, 'ALPHA'
  select 1 as point, * from #mytemp
  exec BETA
  select 2 as point, * from #mytemp
GO

Как вы видите, этот код вызывает внутреннюю процедуру BETA:

create procedure BETA
as
  create table #mytemp (n int, BETA varchar(128))
  insert into #mytemp select 1, 'BETA'
  select 3 as point, * from #mytemp
GO

Выполним процедуру ALPHA и увидим, что каждая процедура видит объекты в своей области видимости. Временные таблицы также доступны, если они не экранированы созданными локально:

две таблицы сосуществуют вместе, в чем можно убедиться добавив оператор -- ***

create procedure BETA
as
  create table #mytemp (n int, BETA varchar(128))
  insert into #mytemp select 1, 'BETA'
  select 3 as point, * from #mytemp
  select * from tempdb.dbo.sysobjects where name like '%mytemp%' -- ***
GO

Вот они, две наши таблички мирно сосуществуют. Мы можем усложнить задачу SQL так:

Я привел скриншот, чтобы обратить внимание на то, что редактор подозревает, что тут ошибка: таблица #mytemp используется после удаления. Но мы знаем, что делаем:

В 3-й отладочной печати выводится локальная таблица, а в 4-й - внешняя, из ALPHA. После drop SQL server вынужден перекомпилировать хвост процедуры, потому что у другой таблицы могут быть другие поля, как в данном случае.

Теперь вас не должно удивить, что произойдет при использовании антипаттерна:

create procedure BETA
as
  if object_id('tempdb..#mytemp') is not null
    DROP TABLE #mytemp  
  create table #mytemp (n int, BETA varchar(128))
  insert into #mytemp select 1, 'BETA'
  select 3 as point, * from #mytemp
GO
Проверьте себя

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

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

Источник: https://habr.com/ru/post/723278/


Интересные статьи

Интересные статьи

В этой статье мы популярно объясняем на собственном опыте как организовать массовую выгрузку, обработку и загрузку фотографий товаров из Bitrix, используя Python и минимальное количество SQL. Для проч...
Часто при разговорах с клиентами мы спрашиваем, как они ведут учет различных данных и используют ли они CRM-систему? Популярный ответ — мы работаем с Excel-файлами, а пот...
Многие компании в определенный момент приходят к тому, что ряд процессов в бизнесе нужно автоматизировать, чтобы не потерять свое место под солнцем и своих заказчиков. Поэтому все...
Однажды, в понедельник, мне пришла в голову мысль — "а покопаюсь ка я в новом ядре" (новым относительно, но об этом позже). Мысль не появилась на ровном месте, а предпосылками для нее стали: ...
Как быстро определить, что на отдельно взятый сайт забили, и им никто не занимается? Если в подвале главной страницы в копирайте стоит не текущий год, а старый, то именно в этом году опека над са...