Хранение данных с кодировкой base64 как BLOB или тип данных TEXT

У нас есть таблица MySQL InnoDB, в которой хранятся ~ 10 столбцов небольших файлов с кодировкой javascript с малым base64 и размером png (< 2KB) base64.

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

Как сейчас, мы используем BLOB для этих столбцов, но мне интересно, есть ли преимущество при переключении на TEXT тип данных с точки зрения производительности или резервного копирования моментальных снимков.

Мои поисковые копания показывают, что BLOB и TEXT для моего случая близки к идентичным, и поскольку я не знаю, перед каким видом данных на самом деле будут храниться, я пошел на BLOB.

Есть ли у вас какие-либо указатели на обсуждение TEXT против BLOB для данного конкретного случая?

Ответ 1

Нельзя хранить данные в формате Base64 в одной базе данных...

Base64 - это средство представления произвольных двоичных данных с использованием только печатных текстовых символов: оно было разработано для ситуаций, когда необходимо передавать такие двоичные данные по протоколу или среде, которые могут обрабатывать только печатный текст (например, SMTP/электронная почта). Это увеличивает размер данных (на 33%) и увеличивает вычислительные затраты на кодирование/декодирование, поэтому его следует избегать, если в этом нет крайней необходимости.

Напротив, весь смысл столбцов BLOB заключается в том, что они хранят необработанные двоичные строки. Так что продолжайте и сохраняйте ваши вещи прямо в столбцы BLOB без предварительной кодировки Base64. Обычно вам нужно хранить связанные метаданные в других столбцах, таких как версия файла/дата последнего изменения, тип носителя и (в случае текстовых файлов, таких как источники JavaScript) кодировка символов. Вы можете решить использовать столбцы типа TEXT для текстовых файлов не только для того, чтобы MySQL автоматически отслеживал кодировку символов для вас, но также для того, чтобы он мог транскодировать в альтернативные наборы символов и/или проверять/манипулировать текстом, как это может быть. требуется (сейчас или в будущем).

(Ошибочная) идея о том, что для баз данных SQL требуются кодировки печатного текста, такие как Base64, для обработки произвольных двоичных данных, увековечена большим количеством плохо информированных руководств. Эта идея, похоже, укоренилась в ошибочном убеждении, что, поскольку SQL включает в себя только печатный текст в других контекстах, он должен обязательно требовать его и для двоичных данных (по крайней мере, для передачи данных, если не для хранения данных). Это просто неверно: SQL может передавать двоичные данные несколькими способами, включая обычные строковые литералы (при условии, что они правильно заключены в кавычки и экранированы, как и любая другая строка); Конечно, предпочтительный способ передачи данных (любого типа) в вашу базу данных - это параметризованные запросы, и параметры могут так же легко содержать двоичные данные, как и все остальное.

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

... если он не был кэширован по соображениям производительности...

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

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

... в этом случае это должно быть TEXT, а не BLOB

Как упоминалось выше, разница между TEXT и BLOB действительно сводится к тому, что столбцы TEXT хранятся вместе с текстовыми метаданными (такими как кодировка и сопоставление символов), тогда как столбцы BLOB не являются, Эти дополнительные метаданные позволяют MySQL транскодировать символы между наборами символов хранения и подключения (где это необходимо) и выполнять эквивалентные/упорядоченные символы.

Вообще говоря: если два клиента, работающие в разных наборах символов, должны видеть одни и те же байты, то вам нужен столбец BLOB; если они должны видеть одинаковые символы, вам нужен столбец TEXT.

С Base64 эти два клиента должны в конечном итоге обнаружить, что данные декодируются в одни и те же байты; но они должны видеть, что закодированные данные имеют одинаковые символы. Например, предположим, что кто-то хочет вставить Base64-кодировку 'Hello world!' (то есть 'SGVsbG8gd29ybGQh'). Если приложение вставки работает в наборе символов UTF-8, оно отправит последовательность байтов 0x53475673624738676432397962475168 в базу данных.

  • если эта последовательность байтов хранится в столбце BLOB и впоследствии извлекается приложением, работающим в UTF-16 *, будут возвращены те же байты, которые представляют '升噳扇㡧搲㥹扇全', а не желаемое значение в кодировке Base64; в то время как

  • если эта байтовая последовательность хранится в столбце TEXT и впоследствии извлекается приложением, работающим в UTF-16, MySQL на лету перекодирует, чтобы вернуть байтовую последовательность 0x0053004700560073006200470038006700640032003900790062004700510068, которая представляет исходную кодировку Base64 значение 'SGVsbG8gd29ybGQh' по желанию.

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


* Actually MySQL does not support using client character sets that are not byte-compatible with ASCII (and therefore Base64 encodings will always be consistent across any combination of them), but this example nevertheless serves to illustrate the difference between [TG420] and [TG421] column types and thus explains why [TG422] is technically correct for this purpose even though [TG423] will actually work without error (at least until MySQL adds support for non-ASCII compatible client character sets).