21

我们有一个 MySQL InnoDB 表,其中包含大约 10 列小型 base64 编码的 javascript 文件和 png(<2KB 大小)图像也经过 base64 编码。

相对而言,插入次数很少,读取次数也很多,但是输出会在 Memcached 实例上缓存几分钟以避免后续读取。

因为现在我们正在使用BLOB这些列,但我想知道在TEXT性能或快照备份方面切换到数据类型是否有优势。

我的搜索挖掘表明BLOBTEXT我的情况几乎相同,因为我事先不知道实际将存储哪种类型的数据,所以我选择了BLOB.

对于这个特定案例,您对 TEXT 与 BLOB 辩论有什么建议吗?

4

1 回答 1

54

不应将 Base64 编码的数据存储在自己的数据库中...

Base64 是一种仅使用可打印文本字符表示任意二进制数据的编码:它设计用于需要通过只能处理可打印文本的协议或介质(例如 SMTP/电子邮件)传输此类二进制数据的情况。它增加了数据大小(增加了 33%)并增加了编码/解码的计算成本,因此除非绝对必要,否则应避免使用。

相比之下,列的全部意义BLOB在于它们存储不透明的二进制字符串。因此,只需继续将您的内容直接存储到您的BLOB列中,而无需先对它们进行 Base64 编码。(也就是说,如果 MySQL 有更适合存储的特定数据的类型,您可能希望使用它:例如,像 JavaScript 源代码这样的文本文件可以从存储在TEXTMySQL 原生跟踪特定文本元数据的列中受益- 更多关于这个下面)。

SQL 数据库需要像 Base64 这样的可打印文本编码来处理任意二进制数据的(错误的)想法已经被大量信息不灵的教程所延续。这个想法似乎是基于一个错误的信念,即因为 SQL 在其他上下文中只包含可打印的文本,所以它肯定也需要二进制数据(至少对于数据传输,如果不是为了数据存储)。这根本不是真的:SQL 可以通过多种方式传达二进制数据,包括纯字符串文字(前提是它们像任何其他字符串一样被正确引用和转义);当然,将数据(任何类型)传递到数据库的首选方式是通过参数化查询,并且参数的数据类型可以很容易地成为原始二进制字符串。

...除非出于性能原因对其进行缓存...

存储 Base64 编码数据可能有一些好处的唯一情况是,它通常在从数据库中检索立即通过需要这种编码的协议(例如通过电子邮件附件)进行传输——在这种情况下,存储 Base64 编码的数据表示将不必在每次提取时对其他原始数据执行编码操作。

但是,请注意,从这个意义上讲,Base64 编码的存储只是充当缓存,就像出于性能原因可能存储非规范化数据一样。

TEXT...在这种情况下不应该BLOB

如上所述:TEXTBLOB列之间的唯一区别是,对于TEXT列,MySQL 还为您跟踪特定于文本的元数据(例如字符编码排序规则)。这个额外的元数据使 MySQL 能够在存储和连接字符集(在适当的情况下)之间转换值,并执行花哨的字符串比较/排序操作。

一般来说:如果两个使用不同字符集的客户端应该看到相同的字节,那么你需要一个BLOB列;如果他们应该看到相同的字符,那么您需要一TEXT列。

使用 Base64,这两个客户端最终必须发现数据解码为相同的字节;但他们应该看到存储/编码的数据具有相同的字符。例如,假设有人希望插入'Hello world!'(即'SGVsbG8gd29ybGQh')的 Base64 编码。如果插入应用程序使用 UTF-8 字符集工作,则它将字节序列发送0x53475673624738676432397962475168到数据库。

  • 如果该字节序列存储在BLOB列中,然后由使用 UTF-16 *的应用程序检索,则将返回相同的字节'升噳扇㡧搲㥹扇全'——它们表示而不是所需的 Base64 编码值;然而

  • 如果该字节序列存储在TEXT列中,然后由使用 UTF-16 的应用程序检索,则 MySQL 将即时转码以返回字节序列0x0053004700560073006200470038006700640032003900790062004700510068——它代表所需的原始 Base64 编码值'SGVsbG8gd29ybGQh'

当然,您仍然可以使用BLOB列并以其他方式跟踪字符编码——但这只会不必要地重新发明轮子,增加维护复杂性和引入意外错误的风险。


* 实际上 MySQL 不支持使用与 ASCII 字节不兼容的客户端字符集(因此 Base64 编码在它们的任何组合中总是一致的),但是这个示例仍然用于说明BLOBTEXT列类型之间的区别,因此解释了为什么TEXT在技术上对此目的是正确的,即使BLOB实际上可以正常工作(至少在 MySQL 添加对非 ASCII 兼容客户端字符集的支持之前)。

于 2012-12-26T15:39:03.730 回答