图片等非机构化数据在数据库中的存储方式
一.现状
通常图片包括商品图片,用户上传的头像以及其他方面的图片。目前业界存储图片有两种做法:
1、 把图片直接以二进制形式存储在数据库中
(1)blob字段类型
一般数据库提供一个二进制字段来存储二进制数据。比如mysql中有个blob字段。oracle数据库中是blob或bfile类型
(2)无blob类型
例如SQL server,没有这种可以直接存储音视频的类型,通常采用代码(例如Java,.net)直接转化成二进制存储在数据库中。采用varchar(max)存储的文本
2、 图片存储在磁盘上(或者文件系统),数据库字段中保存的是图片的路径或URL。
互联网环境中,大访问量,数据库速度和性能方面很重要。一般在数据库存储图片的做法比较少,更多的是将图片路径存储在数据库中,展示图片的时候只需要连接磁盘路径把图片载入进来即可。因为图片是属于大字段。一张图片可能1m到几m。
二、两种方式
1.二进制存储
mysql中一张表的数据是全部在一个数据文件中的。如果大字段的数据也存储在里面。程序展示列表,比如文章列表。这个时候根本不需要展示文章内容的。但是仍然会影响速度,数据库查找数据其实就是扫描那个数据文件,文件容量越小,速度就会越快(为什么单表的容量在1g-2g的时候基本上要分表了)。拆分出去到一张单独的表,就是单独的文件了。我觉得,举一反三,相互独立,分离的思想不仅在系统开发中用到,在现实生活中经常存在的。相互混合,就会造成相互影响。小巧,简洁是一种思想。
2.磁盘(文件系统)
数据库中保存图片路径,一般是这样子的:
按照年月日生成路径。具体是按照年月日还是按照年月去生成路径,根据自己需要(不一定是按照日期去生成)。
图片分散到磁盘路径中去。
数据库字段中保存的是类似于这样子的”images/2012/09/25/ 1343287394783.jpg”
操作系统对单个目录的文件数量是有限制的。当文件数量很多的时候。从目录中获取文件的速度就会越来越慢。所以为了保持速度,才要按照固定规则去分散到多个目录中去。
原来上传的图片文件名称会重新命名保存,比如按照时间戳来生成,1343287394783. jpg。这样子是为了避免文件名重复,多个人往同一个目录上传图片的时候会出现。反正用什么样的规则命名图片,只要做到图片名称的唯一性即可。
比如网站的并发访问量大,目录的生成分得月细越好。比如精确到小时,一个小时都可以是一个文件夹。同时0.001秒有两个用户同时在上传图片(因为那么就会往同一个小时文件夹里面存图片)。因为时间戳是精确到秒的。为了做到图片名称唯一性而不至于覆盖,生成可以在在时间戳后面继续加毫秒微秒等。总结的规律是,并发访问量越大。就越精确就好了。
作者建议,三种东西永远不要放到数据库里,图片,文件,二进制数据。作者的理由是,
对数据库的读/写的速度永远都赶不上文件系统处理的速度
数据库备份变的巨大,越来越耗时间
对文件的访问需要穿越你的应用层和数据库层
三、案例:关于淘宝的图片存储
淘宝以前使用了商用的存储。但是没法满足需求。据说,到2010年,淘宝网后端保存着286亿张图片。商用的系统系统没法满足需求的时候。他们就自己开发了一个tfs。大规模的小文件在磁盘上读取,需要磁盘磁头频繁的寻道和换道。大并发情况下和大量的操作确实很麻烦。其实借鉴了当时google公布的gfs设计论文。google有相册服务。为每个用户提供上传图片存储。
估计,google是率先实现这种小文件网络存储系统的。
有个观点比较好:对于老板们而言,往往觉得,用钱能解决的都不算问题。但问题在于,你遇到的问题,别人都没遇到过。那这个时候你就没有经验可以参考或者直接拿来使用。只有自己参考一些思路去创造技术了。