Skip to content

Плохие привычки: злоупотребление столбцами типа bit

Пересказ статьи Aaron Bertrand. Bad Habits: Abusing bit columns


Я просматриваю много кода DDL от различных команд, и часто встречаю такое:

ALTER TABLE dbo.Widgets ADD IsNotCertified bit NULL;

Когда я вижу битовый столбец, допускающий NULL-значения, то всегда спрашиваю:

Вы намеренно хотите использовать здесь трехзначную логику?
Означает ли NULL что-то отличное от 0, или весь будущий код будет использовать COALESCE, чтобы сравнивать NULL с нулем?

В некоторых случаях NULL и 0 могут иметь различный смысл. Например, битовый столбец может означать включение или выключение установки, а NULL - что установка еще не сконфигурирована, поэтому мы не можем включить её, или же она не допустима для этой сущности. Все это может быть важными фактами, которые нужно различать в нашей бизнес-логике, хотя я, вероятно, предпочел бы столбец типа tinyint для ActiveState, который содержит "включено" (1), "выключено" (0) и еще значения для других возможных состояний.

Хотя чаще да, чем нет, оказывается, что разработчик побоялся добавить столбец с NOT NULL в существующую таблицу, поскольку для древних версий SQL Server это всегда могло вызвать блокировку всей таблицы. (Возможно, это относится к вашей версии/редакции, но тогда я бы ожидал увидеть код, включающий пакетное обновление для установки значения в 0, а затем добавления ограничения NOT NULL.)

И в этом случае при определении битового столбца я также спрашиваю:

Вы на самом деле хотите выразить то, что 1 означает "нет", а 0 - "да"?

Потому что со столбцом IsNot<что-то> неизбежно происходит что-то более странное. Недавно я проверял многооператорную табличнозначную функцию с ужасной производительностью, которая содержала такой код:

/* добавлено M.C. Escher */
INSERT @Awful
SELECT WidgetID,
~COALESCE(IsNotCertified, 0)
FROM dbo.Widgets
WHERE ...

Конечно, сначала я подумал, что DPA вставил какой-то артефакт во время сборки или вывода, или это была опечатка. Но затем я увидел таблицу, определенную выше и понял, что это было сделано намеренно:

RETURNS @Awful table
(
WidgetID int,
IsCertified bit,

Здесь столбец имеет противоположный смысл, чем столбец в таблице, так что мы должны обратить бит (а также учитывать тот факт, что значения NULL возможны, но не означают ничего другого). Эта комбинация провела к использованию побитового NOT, что, я уверен, автор посчитал умным, но совершенно не подумал о будущих читателях, которые, смотря на этот код, будут выглядеть как персонаж Эдварда Мунка:



Но, по крайней мере, это было не так уж плохо:

WHERE NOT (~COALESCE(IsNotCertified, 0) <> -1)

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

INSERT @Awful(WidgetID, IsCertified) /* включение списка столбцов помогает */
SELECT WidgetID,
IsCertified = CASE WHEN IsNotCertified = 1 THEN 0 ELSE 1 END
/* здесь не повредит алиас, согласующийся с именем столбца */
/* комментарий, объясняющий, почему мы преобразуем, тоже не повредит */
FROM dbo.Widgets
WHERE ...

Где это возможно, я либо давал бы столбцу в возвращаемой таблице имя, соответствующее исходному, либо вернулся к проектированию таблицы и заменил его на IsCertified NOT NULL DEFAULT 0 - чтобы 1 означала 1, 0 означал 0, и это все, что нужно сделать.
Категории: T-SQL

Обратные ссылки

Нет обратных ссылок

Комментарии

Показывать комментарии Как список | Древовидной структурой

Нет комментариев.

Автор не разрешил комментировать эту запись

Добавить комментарий

Enclosing asterisks marks text as bold (*word*), underscore are made via _word_.
Standard emoticons like :-) and ;-) are converted to images.

To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA

Form options

Добавленные комментарии должны будут пройти модерацию прежде, чем будут показаны.