Есть ли недостатки в использовании общего varchar (255) для всех текстовых полей? - PullRequest
96 голосов
/ 04 ноября 2008

У меня есть таблица contacts, которая содержит такие поля, как postcode, first name, last name, town, country, phone number и т. Д., Все из которых определены как VARCHAR(255) хотя ни одно из этих полей никогда не приблизится к 255 символам. (Если вам интересно, это так, потому что миграции Ruby on Rails отображают поля String в VARCHAR(255) по умолчанию, и я никогда не удосужился переопределить его).

Поскольку VARCHAR будет хранить только количество фактических символов поля (вместе с длиной поля), есть ли какое-либо явное преимущество (производительность или иное) в использовании, скажем, VARCHAR(16) над VARCHAR(255)?

Кроме того, большинство из этих полей имеют индексы. Влияет ли больший размер VARCHAR на поле на размер или производительность индекса вообще?

К вашему сведению, я использую MySQL 5.

Ответы [ 7 ]

125 голосов
/ 04 ноября 2008

В хранилище VARCHAR(255) достаточно умен, чтобы хранить только нужную вам длину в данном ряду, в отличие от CHAR(255), который всегда будет хранить 255 символов.

Но так как вы пометили этот вопрос MySQL, я упомяну специфический для MySQL совет: поскольку строки копируются из уровня механизма хранения в уровень SQL, поля VARCHAR преобразуются в CHAR, чтобы получить преимущество работы со строками фиксированной ширины. Таким образом, строки в памяти становятся дополненными до максимальной длины вашего объявленного столбца VARCHAR.

Когда ваш запрос неявно генерирует временную таблицу, например, при сортировке или GROUP BY, это может занять много памяти. Если вы используете много полей VARCHAR(255) для данных, которые не должны быть такими длинными, это может сделать временную таблицу очень большой.

Вам также может быть интересно знать, что это поведение "заполнения" означает, что строка, объявленная с набором символов utf8, дополняет до трех байтов на символ, даже для строк, которые вы храните с однобайтовым содержимым (например, символы ascii или latin1) , И также набор символов utf8mb4 заставляет строку заполнять до четырех байтов на символ в памяти.

Таким образом, VARCHAR(255) в utf8, хранящем короткую строку типа «Нет мнения», занимает 11 байт на диске (десять символов младшей кодировки, плюс один байт в длину), но занимает 765 байт в памяти и, следовательно, во временных таблицах или отсортированные результаты.

Я помог пользователям MySQL, которые по незнанию часто создавали временные таблицы 1,5 ГБ и заполняли свое дисковое пространство. У них было много VARCHAR(255) столбцов, которые на практике хранили очень короткие строки.

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

Трудно понять, какой самый длинный почтовый адрес, конечно, поэтому многие люди выбирают длинный VARCHAR, который, безусловно, длиннее любого адреса. И 255 является обычным, потому что это максимальная длина VARCHAR, для которой длина может быть закодирована одним байтом. Это была также максимальная длина VARCHAR в MySQL старше 5.0.

24 голосов
/ 11 августа 2009

В дополнение к размеру и соображениям производительности при настройке размера varchar (и, возможно, более важно, поскольку хранение и обработка становятся дешевле с каждой секундой), недостаток использования varchar (255) «просто потому что» уменьшается целостность данных .

Определение максимальных пределов для строк - это хорошая вещь, которую нужно сделать , чтобы предотвратить попадание строк более длинных, чем ожидалось, в СУБД и вызывать переполнение буфера или исключения / ошибки позднее при извлечении и анализе значений из базы данных, которые длиннее (больше байтов), чем ожидалось.

Например, если у вас есть поле, которое принимает двухсимвольные строки для аббревиатур стран, то у вас нет разумных оснований ожидать, что ваши пользователи (в этом контексте, программисты) будут вводить полные названия стран. Поскольку вы не хотите, чтобы они вводили «Антигуа и Барбуда» (AG) или «Острова Херда и МакДоналда» (HM), вы не разрешаете это на уровне базы данных. Кроме того, вполне вероятно, что некоторые программисты еще не сделали RTFMed проектную документацию (, которая наверняка существует ), чтобы знать, что этого не делать.

Установите поле для приема двух символов и дайте СУБД справиться с ним (либо изящно, усечив, либо неблагоразумно отклонив их SQL с ошибкой).

Примеры реальных данных, у которых нет причин превышать определенную длину:

  • Канадские почтовые коды имеют формат A1A1A1 и всегда имеют длину 6 символов, даже для Санта-Клауса (6 символов исключают пробел, который можно указать для разборчивости).
  • адреса электронной почты - до 64 байт до @, до 255 байт после. Никогда больше, чтобы не сломать Интернет.
  • Североамериканские номера телефонов никогда не должны содержать более 10 цифр (исключая код страны).
  • Компьютеры под управлением (последние версии) Windows не может иметь имен компьютеров, длина которых превышает 63 байта , хотя более 15 не рекомендуется и нарушит ферму серверов Windows NT.
  • Штатные сокращения состоят из 2 символов (например, коды стран указаны выше)
  • Номера для отслеживания ИБП имеют длину 18, 12, 11 или 9 символов. Числа из 18 символов начинаются с «1Z», а цифры из 11 символов начинаются с «T», что заставляет задуматься, как они доставляют все эти пакеты, если они не знают разницы между буквами и цифрами.

И так далее ...

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

Используя varchar (n) вместо varchar (255), вы устраняете проблему, когда пользователи (конечные пользователи, программисты, другие программы) вводят неожиданно длинные данные , которые возвращаются к преследуй свой код позже.

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

13 голосов
/ 04 ноября 2008

В настоящее время я не могу представить, что это действительно имеет значение.

Существуют накладные расходы на использование полей переменной длины, но с учетом избытка процессоров сегодня это даже не стоит учитывать. Система ввода / вывода настолько медленная, что делает невозможными какие-либо вычислительные затраты для эффективной обработки varchars. Фактически, цена varchar в вычислительном отношении, вероятно, является чистым выигрышем над количеством дискового пространства, сэкономленного с помощью полей переменной длины над полями фиксированной длины. Скорее всего, у вас более высокая плотность строк.

Теперь сложность полей varchar заключается в том, что вы не можете легко найти запись по ее номеру. Если у вас фиксированный размер строки (с полями фиксированной длины), вычислить блок диска, на который указывает идентификатор строки, тривиально. С размером строки переменной длины этот вид выходит из окна.

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

Но поскольку у нас сегодня есть поля varchar, единственное значение varchar (16) по сравнению с varchar (255) состоит в том, что DB будет применять ограничение в 16 символов для varchar (16). Если предполагается, что модель БД фактически представляет физическую модель данных, то наличие длин полей может иметь значение. Однако, если это просто «хранилище», а не «модель И хранилище», в этом нет никакой необходимости.

Тогда вам просто нужно различить текстовое поле, которое индексируется (например, varchar), и то, чего нет (например, текстовое поле или поле CLOB). Индексируемые поля обычно имеют ограничение по размеру для облегчения индекса, тогда как поля CLOB этого не делают (в пределах разумного).

13 голосов
/ 04 ноября 2008

Я с тобой. Суетливое внимание к деталям является болью в шее и имеет ограниченную ценность.

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

Если вы используете только поля CHAR, вы можете получить строки фиксированной длины. Это может сэкономить реальное восстановление диска, если вы выбрали точные размеры для полей. Вы можете получить более плотно упакованные данные (меньше операций ввода-вывода для сканирования таблиц) и более быстрые обновления (проще найти открытые пространства в блоке для обновлений и вставок.)

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

Как правило, выигрыш в производительности при попытке задать размер для переменных полей незначителен. Вы можете легко сравнить с помощью VARCHAR (255) по сравнению с CHAR (x), чтобы увидеть, можете ли вы измерить разницу.

Однако иногда мне нужно дать подсказку «маленький», «средний», «большой». Поэтому я использую 16, 64 и 255 для размеров.

5 голосов
/ 04 ноября 2008

По моему опыту, если вы разрешите тип данных из 255 символов, какой-то глупый пользователь (или опытный тестировщик) действительно заполнит это.

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

Гораздо проще выбрать разумный лимит в начале, а затем применить его через приложение и базу данных.

0 голосов
/ 15 декабря 2017

В контексте mysql это может быть важно при работе с индексами в указанных столбцах varchar, так как mysql имеет макс. ограничение в 767 байт на строку индекса.

Это означает, что при добавлении индекса по нескольким столбцам varchar 255 вы можете довольно быстро / даже быстрее достичь этого предела для столбцов utf8 или utf8mb4, как указано в ответах выше

0 голосов
/ 04 ноября 2008

Хорошей практикой является выделять только немного того, что вам нужно. Номера телефонов никогда не станут такими большими.

Одна из причин в том, что если вы не проверяете большие записи, несомненно, кто-то будет использовать все, что есть. Тогда вам может не хватить места в вашем ряду. Я не уверен насчет лимита MySQL, но 8060 - это максимальный размер строки в MS SQL.

Более нормальное значение по умолчанию будет 50 imho, а затем увеличится там, где это необходимо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...