У меня есть приложение (данные хранятся в PostgreSQL), где большинство полей в таблицах всегда не равны NULL, но схема для этих таблиц не обеспечивает этого. Например, посмотрите на эту фальшивую таблицу:
CREATE TABLE "tbl" (
"id" serial,
"name" varchar(40),
"num" int,
"time" timestamp
PRIMARY KEY ("id"),
UNIQUE ("id")
);
Кроме того name
, num
, time
которые явно не указано , как NOT NULL
, в действительности они, потому что исполнение происходит на стороне приложения.
Мне кажется, что это должно быть изменено, но в отличие от этого, уровень приложения гарантирует, что нулевые значения не могут появиться здесь, и никто больше не изменяет таблицу вручную.
Мой вопрос : каковы преимущества (производительность, хранение, согласованность, что-то еще) и недостатки (при условии, что я уже проверил, что в настоящий момент нет нулевых значений, а из бизнес-логики не должно быть нулевых значений), установив явное NOT NULL
ограничение?
У нас есть хороший процесс проверки кода и достаточно хорошая документация, поэтому вероятность того, что какой-то новый человек совершит что-то, что нарушит это ограничение, на самом деле не достаточна, чтобы оправдать это изменение.
Это не мое решение, поэтому именно поэтому я ищу другие оправдания. На мой взгляд, если что-то не может быть нулевым, а база данных позволяет вам указать, что что-то не является нулевым - просто сделайте это. Особенно, если изменение супер просто.
источник
NOT NULL
ограничения не оказывают прямого влияния на размер хранилища. Конечно, со всеми определенными столбцамиNOT NULL
не может быть нулевого растрового изображения для начала. С другой стороны: размер хранилища обычно намного меньше, если вы используете NULL вместо «пустых» или фиктивных значений для столбцов без фактического значения, потому что нулевое растровое изображение сравнительно намного меньше (за исключением случаев редких краев).Ответы:
Что происходит, когда прибывает новый программист, которому нужно написать приложение для этой базы данных? Они не знают , что поле х имеет быть
NOT NULL
.Другая программа может предположить, что все поля x предназначены
NOT NULL
для выполнения подсчета, скажем, но некоторые теперьNULL
из-за новой программы, что приводит к непоследовательности и трудно отследить ошибки.ИМХО, всегда лучше применять правила целостности данных как можно ближе к данным, то есть в базе данных. Таким образом, новые приложения и / или программисты не смогут испортить ваши данные.
Программисты, приложения, языки и фреймворки приходят и уходят. Данные и базы данных, как правило, сохраняются. База данных - это ваша последняя линия защиты от противоречивых, потенциально ошибочных данных.
Сделать максимально использовать ограничение целостности механизмов принуждения вашей базы данных, даже в ущерб производительности. Медленная система, которая дает правильные результаты, бесконечно превосходит быструю, которая ошибается!
источник
IMHO it is always best to enforce data integrity rules as near to the data as possible
на самом деле это то же самое, что и внутреннее чувство, о котором я писал. И именно поэтому я ищу реальные оправдания. У нас есть проверка кода и хорошая документация, поэтому беспокойство о том, что новый разработчик ничего не знает, недостаточно, чтобы оправдать это изменение.REAL PROGRAMMERS
прочитают всю (или даже любую) документацию, прежде чем застрять в проекте, где они находятся в сжатые сроки?Как уже цитированный другими в комментариях, добавляя
NOT NULL
к вашей спецификации таблицы может улучшить в значительном образе выступления ваших запросов (в дополнении к очень хорошим методологическим причинам , изложенные в другом ответе).Причина в том, что оптимизатор запросов, зная, что столбец не может иметь
NULL
значение, может исключить специальные тесты для таких значений, как в случае «NOT IN
против»NOT EXISTS
. Например, вы можете увидеть этот блог , где показано, что отсутствие объявления поляNOT NULL
(когда таблица всегда содержит ненулевые значения) с определенным запросом увеличивает время выполнения на 500%. Результат показан для SQL Server, но подобное поведение может присутствовать и в других реляционных СУБД, таких как ваша (не говоря уже о том, что ваша база данных может быть перенесена в другие системы). Общее правило, которое можно принять, заключается в том, что, когда оптимизатору запросов будет доступно больше информации, могут быть созданы более эффективные планы доступа.источник
NOT NULL
по нескольким причинам, без аргументов по этому поводу. Но ссылка на блог о SQL Server неприменима для Postgres и не доказывает каких-либо последствий для производительности, о которых вы упомянули. Не говорю, что их нет, но я бы хотел увидеть фактические доказательства .not in
для обнуляемых столбцов отличается, хотя в плане между ними должно быть какое-то различие?Космические последствия
О космических последствиях говорит в этом посте @Erwin Brandstetter
Короче говоря, вы сохраните один
totalColumns - 8
бит, округленный до ближайшего байта (илиMAXALIGN
), если ваша база данных имеетNOT NULL
Последствия для производительности
Тем не менее, в этом посте на SE от @Erwin Brandstetter он говорит
У @Renzo есть ответ, в котором говорится о влиянии на производительность - я бы предположил, что ничего из этого не применимо к PostgreSQL . Я не могу найти ничего , что обосновывает любой из что , как имеющие актуальное значение для PostgreSQL. Независимо от того, какие циклы сохранены, их нельзя определить количественно даже в самом элементарном запросе.
Кроме того, я провел несколько тестов, чтобы увидеть, были ли NULL-индексы еще быстрее, и я не смог это доказать. Вы можете найти эту удивительно полезную ветку Скотта Марлоу в списках рассылки, в которой говорится о том, что планировщик запросов в 9.1 может использовать частичный индекс для разнородных предложений WHERE. Я проверил это, запустив следующее
Теперь я создал индексы,
В обоих этих случаях планировщик мог использовать индекс при выборе для
= 10
и использовал последующее сканирование при поиске NULL или 0 соответственно. Оба частичных индекса были одинакового размера. И полные индексы (не показаны) были одинакового размера. Следуя той же методологии, я загрузил таблицу с одной последовательностью1..1e5
, одним значением null / 0 и другой последовательностью1..1e5
. Оба метода смогли найти ноль / 0 с индексом, охватывающим всю таблицу.TLDR; Резюме
Я не могу так или иначе обосновать большинство проблем производительности, которые, по моему мнению, стоили проверить, в том числе недостатки планировщика. Преимущество использования null для сохранения памяти является реальной. Дисковое пространство, сэкономленное благодаря отсутствию нулевого значения, незначительно, и это завышение для таблиц с одним
NULLABLE
столбцом или менее 8 столбцов. В этих случаях не сохраняется место на диске.источник