Значение NULL для полей лучше никогда не использовать. Наличие этого флага увеличивает объём данных при хранении на диске и немного нагружает индексы. Гораздо лучше определять типы полей как NOT NULL и указывать значение по умолчанию (DEFAULT VALUE). Для текста это будет "" (пустая строка), для чисел — 0 (ноль), для дат (DATETIME или TIMESTAMP) — строка "0000-00-00 00:00:00".
Тип ENUM может уменьшить количество используемых таблиц, объём хранимых данных и упростить построение запросов. Но важно помнить, что в поле типа ENUM хранятся толко индексы элементов, а не значения. Сортировка будет происходить тоже по индексам.
Как следствие, JOIN по полю ENUM бесполезен: он не приведёт к ожидаемому результату.
Для хранения произвольных дат (рождения, исторических событий и т.д.), нужно использовать DATETIME.
Внутри базы данные будут храниться в виде целого числа вида YYYYMMDDHHMMSS и занимать 8 байт. Не имеет ограничений дат. Стандартное представление при выборке — текстовая строка в формате YYYY-MM-DD HH:MM:SS. Возвращаемое время не зависит от временной зоны, установленной в MySQL, то есть, выдаются в точности те дата и время, что записаны в базе.
Для хранения текущего времени (дата заметки, комментария или текущего события в логах) — надо использовать TIMESTAMP или INT UNSIGNED. Последний — предпочтительнее.
TIMESTAMP хранит в базе 4-байтное целое число, равное количеству секунд, прошедших с полуночи 1 января 1970 года по усреднённому времени Гринвича (т.е. UNIX-время по Гринвичу). При записи в базу и получении данных используется смещение временной зоны, заданное настройками MySQL. Тип — всегда NOT NULL; значение по умолчанию — всегда NOW(). Представление при выборке — текстовая строка в формате YYYY-MM-DD HH:MM:SS.
TIMESTAMP имеет смысл использовать только в том случае, если используются особенности MySQL для этого типа данных. Вроде автоматической подстройки временной зоны.
INT UNSIGNED хранит данные в том же виде, что и TIMESTAMP, но позволяет полностью контролировать записываемые/считываемые данные. При записи нужно использовать функции конвертирования: например, UNIX_TIMESTAMP() внутри запроса. Представление при выборке — понятно, число.
Поясняющий пример:
mysql> create table datetest(dt datetime, ts timestamp, iu int unsigned);
mysql> insert into datetest(dt,iu) values(NOW(),UNIX_TIMESTAMP(NOW()));
mysql> select * from datetest;
+---------------------+---------------------+------------+ | dt | ts | iu | +---------------------+---------------------+------------+ | 2012-04-05 17:02:45 | 2012-04-05 17:02:45 | 1333630965 | +---------------------+---------------------+------------+
mysql> set @@session.time_zone = '+00:00';
mysql> select * from datetest;
+---------------------+---------------------+------------+ | dt | ts | iu | +---------------------+---------------------+------------+ | 2012-04-05 17:02:45 | 2012-04-05 13:02:45 | 1333630965 | +---------------------+---------------------+------------+
IPv6 — пока ещё экзотика, поэтому речь идёт о IPv4.
Адрес IPv4 представляет собой структуру из 4 байт. Хранить его надо как UNSIGNED INT. Это упрощает хранение, сортировку и выполнение стандартных операции над ip-адресами. Для работы с адресами в привычном представлении можно пользоваться функциями MySQL: INET_ATON() и INET_NTOA().
Поясняющий пример:
mysql> create table iptest(ip int unsigned);
mysql> insert into iptest values (INET_ATON("192.168.0.1"));
mysql> select ip, INET_NTOA(ip),
> INET_NTOA(ip & INET_ATON('255.255.255.0')) as subnet,
> INET_NTOA(ip & INET_ATON('0.0.0.255')) as comp from iptest;
+------------+---------------+-------------+---------+ | ip | INET_NTOA(ip) | subnet | comp | +------------+---------------+-------------+---------+ | 3232235521 | 192.168.0.1 | 192.168.0.0 | 0.0.0.1 | +------------+---------------+-------------+---------+
Пример MD5: cd4278b99534cbfe585b86c4eec29887.
Если нужно хранить в явном виде — используем CHAR(32).
Пример UUID: 8c049922-df7e-400f-9617-7ec36023759d.
Если нужно хранить в явном виде — используем CHAR(36).
Но можно хранить и в BIN(16), преобразовав данные в 16-байтовое число функцией UNHEX(). В UUID перед этим нужно удалить дефисы.
Преобразование из BIN(16) в обычное представление делается функцией HEX().
В MySQL нет специального типа для логических значений. Обычно в этих целях используется тип TINYINT с явной избыточностью (целых 8 бит, хотя фактически используется только один).
Да, я жадный
Поэтому, если в таблице нужно хранить несколько флагов — можно объединить их в одно единственное поле целочисленного типа (до 8 флагов — TINYINT UNSIGNED; от 9 до 16 флагов — SMALLINT UNSIGNED и т.д.), а состояние разных флагов сохранять в значениях разных битов.
Поясняющий пример на PHP:
$flag1 = 1 // 0...0001 $flag2 = 2 // 0...0010 $flag3 = 4 // 0...0100 // Добавляем запись со включенными флагами 1 и 3 // (первый и третий биты, считая с конца): mysql_query("insert into testtable(flags) values({$flag1} | {$flag3})") // Делаем выборку записей, где установлен второй флаг: mysql_query("select * from testtable where (flags & {$flag2}) > 0")
CHAR(n) — для короткого (не больше n байт, n<256) частоизменяемого текста. Не приводит к фрагментации таблицы за счёт хранения избыточных данных (если строка меньше n байт, она дополняется пробелами до n). Быстро сортируется.
VARCHAR(n) — для короткого текста (не больше n байт, n<256), который не будет меняться. Экономит объём хранимых данных, но при частых изменениях — приводит к фрагментации таблицы.
TEXT — для хранения текста до 64 килобайт.
MEDIUMTEXT — для хранения текста размером до 8 мегабайт.
LONGTEXT — до 4 гигабайт текста. Напишите в комментариях, если этот тип кто-то использует.
Последние три типа по понятным причинам тоже могут вызывать фрагментацию таблиц.