Известно, что для MySQL в общем случае не существует линейной зависимости дискового объема, затраченного на хранение данных, от символьной длины этих данных. Классическим примером данной особенности является поведение полей VARCHAR: строка ‘abcd’ занимает 5 байт, будучи помещенной в VARCHAR-поле, и 4 байта, если хранится в CHAR(4) поле. Подробно это явление описано в мануале по адресу
dev.mysql.com/doc/refman/5.1/en/char.html
Однако, затратами на хранение самой строки дело не ограничивается — есть ещё индексы, есть внешние связи, и наверняка ещё что-то, что остается за пределами поля зрения клиента. Что-то, что реагирует на правильный выбор типа и длины поля различным количеством потребляемого дискового пространства.
Мой вопрос в следующем:
есть таблица с полем INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, в которой закончились допустимые значения — всего их для UNSIGNED поля может быть 4294967295, что можно узнать в мануале по адресу
dev.mysql.com/doc/refman/5.1/en/numeric-types.html и на реальном опыте, вставив id в таблицу и попытавшись следующую вставку проделать с использованием auto_increment — получим Duplicate entry '4294967295'. Удалить часть данных из таблицы нельзя, мне необходимо писать в неё дальше. Соответственно, нужно делать ALTER TABLE и менять тип поля на BIGINT, для которого максимальная длина UNSIGNED значения составляет 20 цифр, а максимально значение — 18446744073709551615. Но мне столько не нужно! Айдишники прибавляются с такой скоростью, что мне бы вполне хватило какого-нибудь BIGINT(14) на ближайшие полгода, а там видно будет. Так вот —
какова практическая разница использования BIGINT(M) и BIGINT(20), где 10 < M < 20? Есть сильное подозрение, что использование BIGINT(20) создаст ощутимый перерасход диска и оверхед на I/O в сравнении с BIGINT-полем меньшей длины, но я не смог найти подтверждения этому подозрению.
Известно лишь, что на хранение INT(11) тратится не более 4 байт, а INT(20) —
не более 8.
Об окружении: MySQL 5.1.57, движок InnoDB, проблемное поле является PRIMARY-ключом, на него существуют ссылки по FOREIGN KEY из других таблиц с каскадными CONSTRAINT на UPDATE.
Буду рад услышать ваши мысли по поводу правильного алгоритма выбора длины BIGINT, правильности моих мыслей и о механизмах MySQL, которые имеют дело с заявленной клиентом длиной поля.
А пока что, наученный горьким опытом внезапной остановки продакшена из-за того, что поле уперлось в INT(11), могу пожелать всем администраторам почаще проверять значения автоинкрементных счетчиков в их базах, чтобы не повторить мою судьбу, получив аварию с серьезным даунтаймом на пустом месте.