将base64编码数据存储为BLOB或TEXT数据类型

时间:2012-12-26 15:29:33

标签: mysql text blob innodb

我们有一个MySQL InnoDB表,包含~10列小base64编码的javascript文件和png(< 2KB size)图像base64编码。

相对较少的插入和大量读取,但是输出被缓存在Memcached实例上几分钟以避免后续读取。

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

我的搜索挖掘表明我的情况BLOBTEXT接近相同,因为我事先不知道实际存储的数据类型我去了{{ 1}}。

对于这个具体案例,你对TEXT vs BLOB辩论有什么指示吗?

1 个答案:

答案 0 :(得分:31)

不应该将Base64编码的数据存储在一个数据库中......

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

相比之下, BLOB列的重点是它们存储原始二进制字符串 。因此,只需将您的内容直接存储到BLOB列中,而无需先对它们进行Base64编码。通常,您希望将相关元数据存储在其他列中,例如文件版本/上次修改日期,媒体类型和(如果是文本文件,例如JavaScript源)字符编码。您可能决定对文本文件使用TEXT类型列,这样不仅可以使MySQL本身跟踪字符编码,还可以将其转码为替代字符集和/或检查/操作文本为可能需要(现在或将来)。

SQL数据库需要像Base64这样的可打印文本编码来处理任意二进制数据的(错误的)观念已经被大量不明智的教程所延续。这个想法似乎是错误地认为,因为SQL在其他环境中只包含可打印文本,所以它必定也需要它用于二进制数据(至少对于数据传输,如果不是用于数据存储)。事实并非如此:SQL可以通过多种方式传递二进制数据,包括纯字符串文字(前提是它们被正确引用并像任何其他字符串一样进行转义);当然,将数据(任何类型)传递到数据库的首选方法是通过参数化查询,参数可以像包含其他任何内容一样容易地包含二进制数据。

对于它的价值,我通常完全避免在RDBMS中存储这样的项目,而宁愿使用那些高度优化的文件存储数据库,称为 filesystems ,但这完全是另一回事。

...除非出于性能原因而缓存...

存储Base64编码数据可能带来一些好处的唯一情况是数据经常从数据库中检索并通过需要编码的协议传输 - 在这种情况下,存储Base64编码的表示将节省从每次获取时必须对原始数据执行编码操作。

但是,请注意,Base64编码的存储仅仅充当缓存,就像出于性能原因存储非规范化数据一样。

...在这种情况下,它应该是TEXT而不是BLOB

如上所述,TEXTBLOB之间的差异实际上归结为TEXT列与特定于文本的元数据(例如字符)一起存储的事实编码整理),而BLOB列不是。这个额外的元数据使MySQL能够在存储和连接字符集之间转换字符(如果适用),并执行奇特的字符等效/排序。

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

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

  • 如果该字节序列存储在BLOB列中,后来由一个工作在UTF-16中的应用程序检索,将返回相同的字节 - 它代表'升噳扇㡧搲㥹扇全'而不是所需的Base64编码值;而

  • 如果该字节序列存储在TEXT列中,后来由一个工作在UTF-16中的应用程序检索,MySQL将动态转码以返回字节序列{{1 } - 表示所需的原始Base64编码值0x0053004700560073006200470038006700640032003900790062004700510068

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