Когда использовать TINYINT поверх INT?

91

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

Например, лучше использовать, tinyintкогда вы знаете, что единственные данные, которые вы будете хранить, это 1, 0 или ноль (с очень малой вероятностью увеличения их до 2 или 3 позже).

Тем не менее, единственная причина, по которой я знаю это, заключается в хранении - использование 1 байта в строке вместо 4 байтов.

Каковы последствия использования tinyint(или smallintдаже bigint) всего лишь intпомимо экономии места на жестком диске?

Ричард
источник
2
Это очень хороший вопрос (+1). В MySQL есть SELECT ... PROCEDURE ANALYZE (), который фактически рекомендует наименьшие типы данных, которые должна иметь таблица для данного SELECT. Это было частично вдохновением моего ответа.
RolandoMySQLDBA
3
Хороший вопрос, но для уточнения диапазона tinyint это 0-255. Битовое поле равно 0 или 1 (или NULL). Стоимость хранения для tinyint составляет 1 байт. Каждые 8-битные поля в таблице будут стоить 1 байт памяти. msdn.microsoft.com/en-us/library/ms187745.aspx и msdn.microsoft.com/en-us/library/ms177603.aspx
billinkc
@billinkc Верно. Вот почему я упомянул о возможности расширения столбца, чтобы включить значения 2 или 3. Если вы включите 2 или 3, вы должны использовать tinyint (в очень маленьком масштабе).
Ричард
1
«Например, лучше использовать tinyint, если вы знаете, что единственные данные, которые вы будете хранить, это 1, 0 или ноль (с очень малой вероятностью увеличения их до 2 или 3 позже)». Я бы использовал ENUM для такой вещи. Они хранятся в виде битовых полей, и, как отмечали многие другие, небольшая экономия на запись в целом приводит к большой экономии по всей базе данных - даже более того, если столбец проиндексирован.
2
@ user6665 I'd use an ENUM for such a thing.Не в SQL Server, вы бы не сделали, так как он не имеет каких-либо перечислений.
underscore_d

Ответы:

92

Дисковое пространство дешево ... это не главное!

Перестаньте думать о пространстве хранения, подумайте вместо этого о пуле буферов и пропускной способности хранилища . В крайнем случае, кэш- память процессора и пропускная способность шины памяти . Связанная статья является частью серии, освещающей проблемы с плохим выбором кластеризованного ключа (INT против GUID против последовательного GUID), но она подчеркивает разницу в байтах.

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

Мне напоминают об окружающей среде, описанной в предыдущем вопросе . Более 400 баз данных размером от 50 МБ до 50 ГБ для каждого экземпляра SQL. Очистка нескольких байтов на запись, таблицу, базу данных в этой среде может существенно изменить ситуацию.

Марк Стори-Смит
источник
29

В дополнение к другим ответам ...

Строки и записи индекса хранятся в 8 тыс. Страниц. Таким образом, миллион строк по 3 байта на строку - это не 3 МБ на диске: это влияет на количество строк на странице («плотность страниц»).

То же самое относится к nvarchar к varchar, smalldatetime к datetime, int к tinyint и т. Д.

Редактировать, июнь 2013

http://sqlblog.com/blogs/joe_chang/archive/2013/06/16/load-test-manifesto.aspx

В этой статье говорится

Важными критериями являются количество элементов и соотношение страниц к строкам.

Таким образом, выбор типа данных имеет значение

ГБН
источник
5
Хорошая точка зрения. Абсолютным худшим примером является строка длиной 4028 байт, состоящая из столбцов с полностью фиксированной длиной, к которым вы хотите добавить столбец. Добавление smallint приведет к значению 4030 (2 строки на страницу), но int будет выталкивать вас за границу (1 строка на страницу, тратится 4028 байт на страницу).
Марк Стори-Смит
Однажды я сделал тест производительности на INT против Bigint. Сохранение 1 миллиона записей, сравнение времени и хранилища и извлечение их одна за другой, снова измеряя производительность. Я не видел больших различий. Я собираюсь сделать тот же тест производительности для INT против tinyint. Я действительно думаю, что им можно пренебречь для 80% приложений, что приводит к более согласованным типам данных и меньшим затратам на обслуживание.
Саид Нямати
1
@SaeedNeamati Возможно, вы захотите перечитать статью из ответа МаркаВы когда-нибудь слышали ... давайте просто покончим с этим - мы будем беспокоиться о производительности позже? ... Я слышу это все время… »), и gbn здесь , Я думаю, что дело в том, что любой неэффективный выбор покажет свои полосы в правильном масштабе, и интуиция OP не ошибается.
ruffin
14

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

Я определенно ожидал бы обнаружить, что изучение записей индекса на страницах BTREE будет немного быстрее с меньшими типами данных. Однако любые VARCHAR, участвующие в элементах индекса, компенсируют (сводят на нет) выигрыш в производительности от использования TINYINT над INT.

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

RolandoMySQLDBA
источник
13

Все становится сложнее, когда базы данных становятся больше:

  • окна обслуживания должны быть увеличены или перенесены
  • резервное копирование (полное резервное копирование на конец дня становится абсурдным пожирателем времени, поэтому вам нужно делать разностные или даже журнальные резервные копии и выполнять полное резервирование раз в неделю, может, раз в месяц)
  • показатели производительности становятся затратами времени (создание индекса для таблицы с многомиллионными строками занимает не тривиальное время), его необходимо перенести и ухудшить, если таблица широкая ...
  • И передача этой резервной копии 100 Гбит через сеть - это не то, что я называю легкой задачей - особенно если сеть (по неизвестной причине) упряма при разрыве соединения на отметке 75 ГБ ... (произошло с установкой, на которой я работал, что было резервное копирование на подключенный диск в сети - сети) ...

И какие типы данных имеют к этому отношение? ВСЕ. Использование размеров строк, превышающих необходимые, приводит к тому, что страницы базы данных заполняются раньше, чем необходимо, или даже тратят пространство, если размер строки таков, что на странице может быть записано не более одной записи. В результате для записи и чтения требуется больше страниц, для кеширования используется больше оперативной памяти (для больших записей требуется больше памяти). И так как ваши типы данных определены больше, чем необходимо для диска, ваши индексы будут страдать от той же проблемы - особенно если вы кластеризуете этот составной первичный ключ 2 столбцов BIGINT, так как любые другие созданные индексы будут неявно копировать этот первичный ключ при их определении.

Если вы знаете, что некоторые столбцы в таблице содержат миллионы строк или даже небольшую таблицу, которая будет преобразована в FK в многомиллионную строку, для которой не нужно 4-байтовое целое число для хранения своих данных, но 2-байтовый будет достаточно - используйте SMALLINT . Если значений в диапазоне 0-255 достаточно, TINYINT . Флаг Да / Нет? Там БИТ .

Фабрицио Араужо
источник
9

В то время как для tinyintvs intесть явные различия, такие как дисковое пространство, разбиение страниц и время обслуживания, их не будет varchar.

Так почему бы не объявить все текстовые поля как varchar(4000), поскольку они в любом случае будут использовать только необходимое пространство? Более того, вам гарантировано, что ваши данные никогда не будут усечены.

Ответ, конечно:

  1. Разъяснение ваших намерений (поскольку никто не поймет, почему поле имени должно быть 4000 символов)
  2. Проверка правильности, поскольку вы хотите убедиться, что никто не вводит всю биографию в качестве имени.

Эти же самые причины относятся и к tinyint.

Йоэл Хэлб
источник
3
Это старая ветка, но уточнение и проверка не единственная причина. Если у вас есть VARCHAR (4000) для чего-то, что должно быть VARCHAR (20), план запроса будет думать, что ваши требования к памяти и процессору во много раз больше, чем они должны быть в отношении этого столбца. Я не потратил время, чтобы сделать это, но я предполагаю, что вы, вероятно, можете увидеть это, посмотрев план запроса для VARCHAR (20), а затем измените на VARCHAR (4000) и проверьте расчетные затраты.
3
@ GeorgeShouse Демонстрация этого здесь
Мартин Смит