Насколько либеральным должен быть столбец NOT NULL? - PullRequest
23 голосов
/ 18 марта 2009

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

Должен ли я помечать как НЕДЕЙСТВИТЕЛЬНЫЕ только те столбцы, которые абсолютно должны быть заполнены для строки, чтобы иметь какое-либо значение для моего приложения?

Или я должен отметить все столбцы, которые я намерен никогда не быть нулевым?

Какое влияние на производительность оказывает небольшое или большое количество столбцов NOT NULL?

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

Может ли кто-то с большим знанием, чем я, дать мне низкий уровень?

Ответы [ 15 ]

27 голосов
/ 18 марта 2009

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

14 голосов
/ 18 марта 2009

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

"Должен ли я отмечать как НЕ НУЛЬНЫЕ только те столбцы, которые обязательно должны быть заполнены для того, чтобы строка имела какое-либо значение для моего приложения?"

Да. Это так просто. Вам гораздо лучше с NULLable столбцом без каких-либо значений NULL в нем, чем с потребностью в NULL и необходимостью имитировать его. И в любом случае, любые неоднозначные случаи лучше отфильтровывать в ваших бизнес-правилах.


EDIT:

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

11 голосов
/ 18 марта 2009

Ошибка на стороне NOT NULL. В какой-то момент вам придется решить, что означает «NULL» в вашем приложении - скорее всего, для разных столбцов это будет по-разному. Некоторые из распространенных случаев: «не указано», «неизвестно», «неприменимо», «еще не произошло» и т. Д. Вы будете знать, когда вам нужно одно из этих значений, а затем вы можете соответствующим образом разрешить столбец NULLable и код логики вокруг него.

Разрешение случайным вещам быть NULL, рано или поздно, всегда IME кошмара. Используйте NULL осторожно и экономно - и знайте, что это значит в вашей логике.

Edit: Кажется, есть идея, что я спорю о NO пустых столбцах, когда-либо. Это нелепо. NULL полезен, но только там, где ожидается.

Хороший пример - пример Le Dorfier DateOfDeath. NULL DateOfDeath будет означать «еще не произошло». Теперь я могу написать представление LivingPersons WHERE DateOfDeath IS NULL.

Но что означает NULL OrderDate? Что заказ еще не сделан? Даже если есть запись в таблице заказов? Как насчет пустого адреса? Именно эти мысли должны пройти через вашу голову, прежде чем вы позволите NULL быть значением.

Назад к DateOfDeath - запрос лиц WHERE DateOfDeath > '1/1/1999' не будет возвращать записи NULL - даже если мы логически знаем, что они должны умереть после 1999 . Это то, что вы хотите? Если нет, то вам лучше включить OR DateOfDeath IS NULL в этот запрос. Если вы разрешите все столбцы иметь значение NULL, вам придется думать об этом каждый раз, когда вы пишете запрос . IME, это слишком много для умственного налога для 10% или около того столбцов, которые на самом деле имеют законное значение, когда они равны NULL.

10 голосов
/ 18 марта 2009

Я обнаружил, что пометка столбца как NOT NULL - это, как правило, хорошая идея, если у вас нет полезного значения NULL в столбце. В противном случае вы можете неожиданно найти NULL там позже, когда поймете, что вам это не нужно, и изменить сложнее.

9 голосов
/ 18 марта 2009

Я стараюсь максимально избегать использования значений NULL в базе данных. Это означает, что символьные поля всегда не равны NULL. То же самое для числовых полей, особенно для обозначения денег или аналогичных (доли, единицы и т. Д.)

У меня есть 2 исключения:

  1. Даты, когда дата может быть неизвестна (например, DivorcedOn)
  2. Необязательные внешние ключевые отношения (MarriedToPersonId). Хотя иногда я использовал «пустые» строки в таблице внешних ключей и сделал обязательным отношение (например, JobDescriptionCode)

Я также иногда использовал явные битовые поля для «неизвестно» / «не установлено» (например, JobDescriptionCode и IsEmployeed).

У меня есть несколько основных причин, по которым:

  1. NULL всегда будут вызывать проблемы в числовых полях. Всегда. Всегда. Всегда. Неважно, насколько вы осторожны, выберите X + Y, так как произойдет Total, и он вернет NULL.
  2. NULL могут легко вызывать проблемы в строковых полях, обычно в адресных полях (например, выберите AddrLine1 + AddrLine2 из Адреса).
  3. Защита от NULL на уровне бизнес-логики - утомительная трата усилий ... просто не допускайте их в БД, и вы можете сохранить сотни строк кода.

Мои предпочтительные значения по умолчанию:

  • Strings -> "", иначе пустая строка
  • Числа -> 0
  • Даты -> Сегодня или NULL (см. Исключение № 1)
  • Бит -> ложь
7 голосов
/ 18 марта 2009

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *. Вы можете получить представление о его идеях в этом интервью , где он говорит, среди прочего:

Так что да, я думаю, что SQL довольно плох. Но вы явно спрашиваете, какова его основная недостатки есть. Ну вот несколько:

  • Дубликаты строк
  • Нулевые
  • Порядок столбцов слева направо
  • Безымянные столбцы и повторяющиеся имена столбцов
  • Неспособность правильно поддерживать "="
  • 1021 * Pointers *
  • Высокая избыточность

По моему опыту, почти все "запланированные нули" могут быть лучше представлены дочерней таблицей, имеющей внешний ключ к базовой таблице. Участие в дочерней таблице не является обязательным, и именно здесь фактически делается различие между нулем / не нулем.

Это хорошо согласуется с интерпретацией отношения как логического предложения первого порядка. Это тоже просто здравый смысл. Когда кто-то не знает адрес Боба, он пишет в своем Rolodex:

Bob. ____

Или кто-то просто воздерживается от заполнения адресной карты для Боба, пока у него не появится фактический адрес для него?

Редактировать: Аргумент даты появляется на страницах 53-55 Глубины базы данных под заголовком раздела " Почему запрещены пустые значения ."

4 голосов
/ 19 марта 2009

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

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

Несколько общих значений для нуля:

  • Все, что приходит непосредственно от пользователя
    • Здесь ноль означает «пользователь не вошел»
    • Для этих столбцов лучше разрешить пустые значения, иначе вы просто получите ввод типа asdasd@asd.com.
  • Внешние ключи для отношений "0 или 1"
    • null означает «нет связанной строки»
    • Так что разрешите пустые значения для этих столбцов
    • Это один противоречивым , но это мое мнение.

В общем, если вы не можете придумать полезного значения для нуля в столбце, это должно быть NOT NULL. Вы всегда можете изменить его на nullable позже.

Пример того, с чем я закончил:

create table SalesOrderLine (
    Id int identity primary key,
    -- a line must have exactly one header:
    IdHeader int not null foreign key references SalesOrderHeader, 
    LineNumber int not null, -- a line must have a line number
    IdItem int not null, -- cannot have null item
    Quantity decimal not null, -- maybe could sell 0, but not null
    UnitPrice decimal not null, -- price can be 0, but not null
    -- a null delivery address means not for delivery:
    IdDeliveryAddress int foreign key references Address, 
    Comment varchar(100), -- null means user skipped it
    Cancelled bit not null default (0) -- true boolean, not three-state!
    Delivered datetime, -- null means not yet delivered
    Logged datetime not null default (GetDate()) -- must be filled out
)
4 голосов
/ 18 марта 2009

Я склоняюсь к НЕ НУЛЬ, если не вижу другой причины - как кто-то сказал, нравится это или нет, странный особый случай - НУЛЬ.

Один из моих фаворитов в отношении NULL:

SELECT F1 FROM T WHERE F2 <> 'OK'

... который (по крайней мере, в DB2) не будет содержать строк, где f2 равен нулю, потому что в реляционном жаргоне (NULL <> 'OK') равен NULL. Но ваше намерение было вернуть все не-ОК строки. Вам нужен дополнительный предикат ИЛИ, или вместо этого напишите F2 DISTINCT FROM 'OK' (что, в первую очередь, является специальным кодированием).

IMO, NULL - это всего лишь один из тех инструментов программиста, как арифметика указателей или перегрузка операторов, который требует столько же искусства, сколько наука.

Джо Селко пишет об этом в SQL For Smarties - ловушка использования NULL в приложении заключается в том, что его значение, ну, в общем, не определено. Это может означать неизвестный, неинициализированный, неполный, неприменимый - или, как в немом примере выше, означает ли это ОК или нет - ОК?

2 голосов
/ 18 марта 2009

Лично я думаю, что вы должны пометить столбцы как Нулевые или не нулевые в зависимости от того, какие данные они содержат, если есть реальное требование, чтобы данные всегда были там, и всегда ли данные известны во время вход. Если пометить столбец как ненулевой, когда у пользователей нет данных, он будет вынужден составить данные, которые сделают все ваши данные бесполезными (таким образом, вы получите ненужные данные, такие как поле электронной почты, содержащее "thisissilly@Ihatethisaplication.com «). Неспособность потребовать что-то, что должно быть там, чтобы процесс работал (скажем, ключевое поле, чтобы показать, какой клиент сделал заказ) одинаково глупо. Ноль Недостаток, а не ноль - это проблема целостности данных, делайте то, что имеет больше смысла, чтобы ваши данные можно было использовать.

2 голосов
/ 18 марта 2009

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

...