Кодирование хранимого значения СУБД с помощью конечного стража для обнаружения усечения / повреждения; профи? минусы? альтернативы?
Недавно группа, которую я поддерживаю, столкнулась с проблемой со значением, которое они хранили (и извлекали) из базы данных MySQL. Они говорят мне, что хранили значение с разделителями-запятыми в столбце (VARCHAR(255)?).
Они сообщили, что их значение было молча усечено (их код в основном Ruby, некоторая другая обработка выполняется в Scala) и попросили нас удвоить размер этого столбца.
Естественно, я предложил, чтобы они нормализовали... хранили каждое из этих значений (ранее разделенных запятыми) в отдельных строках и использовали SELECT для извлечения набора (который раньше был бы одной строкой). Они отодвинулись и настаивают на том, что им никогда не нужны эти разделенные значения для любого другого вида запроса к базе данных, и что им никогда не понадобится, чтобы поле было шире, чем новая (512) ширина.
Затем я предложил, чтобы они хотя бы добавили часового, отмечающего конец их строки (в частности, конечную точку с запятой), и проверяли это во всех выборках. Они реализовали это и довольны таким подходом.
Мои вопросы:
- Как их данные молча усекались? Есть ли какие-то настройки в MySQL или в их драйверах БД для Ruby, которые подавляют ошибку?
- Каковы плюсы и минусы этого терминированного значения по сравнению с более нормализованным подходом?
- Есть ли какой-либо термин искусства или псевдоним для этого термина прекращено значение?
- Что может быть лучше для решения их проблемы?
2 ответа
Если в вашей базе данных не включен строгий режим, MySQL будет обрезать строки, которые не вписываются в varchar(n)
столбец и выдают только предупреждение об усечении. Если вы включите строгий режим, то в таких случаях вы получите ошибку (и больше душевного спокойствия).
Большая проблема с вашим значением Sentinel заключается в том, что они проверяют его только на чтение. Это означает, что они могут (и, безусловно, будут) хранить неверные / поврежденные данные, но не будут знать о проблеме до тех пор, пока не попытаются распаковать эти данные; но когда они распаковывают данные, будет слишком поздно, чтобы восстановить то, что было потеряно.
Есть несколько лучших подходов:
- Правильно нормализованные таблицы.
- Включить строгий режим в MySQL.
- Предварительная вставка или предварительное обновление проверки длины.
- Если они на самом деле используют Rails, то, возможно, они могли бы использовать
serialize
автоматически конвертировать данные в / из (cringe) YAML; в этом случае им придется использовать больший тип столбца TEXT, и у них все еще будет проблема с усечением.
Таким образом, 2 и 3 должны быть выполнены немедленно, 1 будет лучшим, 4 может быть средним вариантом, если они боятся (или не понимают) нормализации.
На самом деле довольно просто "пропустить" усечение в MySQL, но также довольно легко заставить его строго уведомлять вас, вместо того, чтобы пытаться быть полезным.
Из руководства MySQL:
Если режим строгого SQL не включен и вы присваиваете столбцу CHAR или VARCHAR значение, которое превышает максимальную длину столбца, это значение усекается, чтобы соответствовать, и генерируется предупреждение. Для усечения непространственных символов вы можете вызвать ошибку (а не предупреждение) и запретить вставку значения, используя строгий режим SQL. Смотрите Раздел 5.1.6, "Режимы SQL сервера".
Как указано в руководстве, вы можете установить один из нескольких "строгих" режимов MySQL, чтобы в этой ситуации возникла ошибка (и многие другие, которые в противном случае могли бы привести к тихому усечению или замене значений).