Когда использовать NULL в таблицах MySQL - PullRequest
48 голосов
/ 23 января 2009

Я ценю семантическое значение значения NULL в таблице базы данных, отличающегося как от false, так и от пустой строки ''. Тем не менее, я часто читал о проблемах производительности, когда поля обнуляются, и мне посоветовали использовать пустую строку в случаях, когда NULL на самом деле семантически правильно.

Какие обстоятельства подходят для использования пустых полей и значений NULL? Каковы компромиссы? Разумно ли вообще избегать использования значений NULL и просто использовать пустые строки, false или 0, чтобы указать на отсутствие значения?

UPDATE

ОК. Я понимаю семантическое различие между '' и NULL, а также (не зависящие от производительности) обстоятельства, при которых NULL является подходящим значением поля. Тем не менее, позвольте мне подробнее остановиться на проблеме производительности. Это из превосходного "Высокопроизводительного MySQL" Шварца, Зейцева и др. http://www.borders.co.uk/book/high-performance-mysql-optimization-backups-replication-and-more/857673/:

MySQL труднее оптимизировать запросы, которые относятся к обнуляемым кумнам, потому что они делают индексы, индекс статистика и сравнение ценностей больше сложно. Обнуляемый столбец использует больше места для хранения и требует специальная обработка внутри MySQL. когда обнуляемый столбец индексируется, это требуется дополнительный байт на запись и может даже вызвать фиксированный размер (например, указатель на одно целое число столбец) для преобразования в переменный размер в MyISAM.

Больше здесь: Просмотр книг Google

Вполне возможно, что окончательный ответ - я просто искал второе мнение и опыт с фронта.

Ответы [ 11 ]

37 голосов
/ 23 января 2009

Однако я часто читал о проблемы с производительностью, когда поля обнуляется и было рекомендовано использовать пустая строка в случаях, когда NULL на самом деле семантически правильно.

Я собираюсь быть придирчивым к выбору слов на мгновение:

  • Даже если бы это был значительный фактор производительности, это не делает семантически правильным для использования значения вместо NULL. В SQL NULL выполняет семантическую роль для обозначения отсутствующего или неприменимого значения. Характеристики производительности NULL в данной реализации СУБД не зависят от этого. Производительность может варьироваться от бренда к бренду или от версии к версии, но цель NULL на языке постоянна.

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

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

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

В MySQL для поиска NULL может быть полезен индекс:

mysql> CREATE TABLE foo (
  i INT NOT NULL,
  j INT DEFAULT NULL,
  PRIMARY KEY (i),
  UNIQUE KEY j_index (j)
);

mysql> INSERT INTO foo (i, j) VALUES 
  (1, 1), (2, 2), (3, NULL), (4, NULL), (5, 5);

mysql> EXPLAIN SELECT * FROM foo WHERE i = 3;
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
|  1 | SIMPLE      | foo   | const | PRIMARY       | PRIMARY | 4       | const |    1 |       | 
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+

mysql> EXPLAIN SELECT * FROM foo WHERE j IS NULL;
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key     | key_len | ref   | rows | Extra       |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
|  1 | SIMPLE      | foo   | ref  | j_index       | j_index | 5       | const |    2 | Using where | 
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+

Обратите внимание, что это еще не показатель производительности. Я только показал, что вы можете использовать индекс при поиске NULL. Я собираюсь утверждать (по общему признанию, не измеряя, но эй, это просто StackOverflow), что преимущество индекса затмевает любое возможное наказание при поиске NULL по сравнению с пустой строкой.

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

11 голосов
/ 23 января 2009

В руководстве по MySQL есть хорошая статья о проблемах с NULL.

Надеюсь, это поможет.

Также нашел этот другой ТАК пост о NULL и производительности

5 голосов
/ 27 января 2009

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

MyVal = COALESCE(TheData, 0)

Поскольку мы выполняем массовую вставку данных из плоских файлов, мы используем файлы форматирования для определения ввода данных, который в любом случае автоматически преобразует пустые значения в пустые строки.

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

3 голосов
/ 23 января 2009

Обычно, если атрибут требуется, он определяется как Не NULL, а если он может быть опущен, он определяется как обнуляемый.

2 голосов
/ 01 июля 2013

Как сказал @ForYourOwnGood - Null должен использоваться для «неизвестной» информации. Например: если у вас много полей, которые клиент должен заполнить при регистрации, и некоторые из них являются необязательными. По какой-то причине вам может потребоваться зарезервировать идентификатор для этого конкретного клиента, и, поскольку вы не знаете, являются ли необязательные поля реальным выбором покупателя оставить пустым, вы должны установить их как NULL, то есть «неизвестно» при первом сохранении ряд. Если клиент отправляет форму, проходит все ваши проверки и затем вы сохраняете информацию, то вы точно знаете, что дополнительное поле намеренно оставлено пустым.

Это просто хороший пример использования NULL.

2 голосов
/ 23 января 2009

Пустая строка не должна использоваться вместо NULL. NULL ничего не представляет где пустая строка является чем-то, ни с чем внутри. NULL всегда будет ложным при сравнении с другим значением (даже NULL), а NULL не будет суммироваться в функции COUNT.

Если вам необходимо представить неизвестную информацию, ее нельзя заменить NULL.

1 голос
/ 06 июля 2018

Я понимаю, что бывают ситуации, когда семантика NULL в MySQL полностью уместна.

Тем не менее, они серьезно мешают, особенно с текстовыми полями.

Вот пример из реального мира.

Мы хотим скопировать данные из базы данных FileMaker в таблицу mysql.

если мы сделаем «SELECT * from table, где textfield <> 'test'", строки с текстовым полем NULL НЕ будут возвращены. Скорее всего, это не то, что вы ожидали или хотели.

если поле, которое имеет значение NULL, используется в запросе where, отдельно или как часть AND, записи, которые имеют значение NULL, НИКОГДА не будут возвращены, если не используется тест IS NULL. Мы должны сделать что-то вроде «где ((текстовое поле <>« тест ») ИЛИ (текстовое поле НЕ НУЛЬ))», что в лучшем случае ужасно.

Так что в этом случае мы, вероятно, не хотим, чтобы поле обнулялось.

Проблема в том, что вы НЕ МОЖЕТЕ вставить пустую строку в MySQL с помощью Filemaker. Он преобразуется в NULL, что приводит к ошибкам, если вы сделали столбец не нулевым! Если вы разрешите NULL, тогда передача в mysql работает, но тогда ваши запросы не будут работать так, как вы хотите!

В этом случае необходимо дважды изменить таблицу, преобразовать существующие значения null после импорта в пустую строку, а затем изменить таблицу, чтобы снова разрешить null. youch!

чертов файлмейкер.

1 голос
/ 23 января 2009

Значение столбца NULL более или менее "не применимо в этом контексте". Я обычно использую NULL столбцы в двух случаях:

  • Если поле не применяется (допустим, у вас есть логический столбец is_thirsty и вы добавляете два набора данных. Один человек и камень. В случае человека вы устанавливаете для is_thirsty значение true или false, тогда как в случае камня, вы, вероятно, установите его в NULL.
  • Если мне нужно что-то пометить и сохранить некоторые данные со значением. Как и дата закрытия инвентаря, которую вы использовали бы, чтобы: а) указать, что инвентарь больше нельзя изменить, и б) указать, когда инвентарь был закрыт. Вместо двух столбцов (closed_at и is_closed) я просто создаю столбец closed_at и устанавливаю его в NULL, если набор инвентаря все еще можно изменить, но устанавливаю дату после его закрытия.

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

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

Кроме того, NULL не равен чему-либо, что повредит запросам повсюду, если вы не очень осторожны.

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

1 голос
/ 23 января 2009

Главным преимуществом, конечно же, является семантическое значение NULL, о котором вы упомянули.

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

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

0 голосов
/ 23 января 2009

В некоторых базах данных, таких как Oracle, может быть что-то похожее на MySQL:

  • Нули не индексируются, поэтому поиск нулевых значений может стать узким местом.
  • Завершающие нули в строках экономят место.
...