将文档以Blob形式存储在数据库中 - 有什么不利之处吗?
将文档以Blob形式存储在数据库中 - 有什么不利之处吗?
我的文档管理系统的要求是:
- 必须能够防止通过简单复制目录、文件等方式进行盗窃。
- 必须能够防止传统病毒感染(对物理文件的感染)。
- 检索速度必须快。
- 仓库不能对普通(目录)浏览用户可见。
我决定将所有文档(和扫描图像)以二进制大对象(BLOB)的形式存储在数据库中,到目前为止,我的经验非常好,文档检索速度极快 - 它满足了上述所有标准,甚至还有一些额外的优势,比如自动将文档与相关实体一起存储,方便快捷地搜索内容,删除与打开和命名文档有关的各种用户活动等等。
我的问题是 - 这种设计和实现是否存在任何严重的风险或我忽视的事项?
编辑说明:数据库是PostgreSQL,能够很好地处理BLOB,并且具有出色的扩展性。环境是多用户环境。
在数据库中将文档存储为BLOB存在的主要缺点是,当文件大小超过一定限制时,文件系统在存储和检索大文件方面比数据库更高效。根据您列出的要求,似乎您已经考虑到了这一点。
有一个良好的参考资料(PDF),其中涵盖了BLOB的优缺点。
那么为什么会出现使用BLOB存储文档的缺点呢?一方面,数据库的设计初衷是用于存储结构化数据,而非大型文件。因此,在存储和检索大文件时,数据库的性能可能会受到影响。另一方面,文件系统专门用于处理文件,因此对于大文件的存储和检索更加高效。
那么如何解决这个问题呢?一种解决方法是将大文件存储在文件系统中,而在数据库中存储文件的元数据信息,例如文件路径、大小、创建日期等。这样可以将大文件的存储和检索交给文件系统来处理,同时保留数据库的优势,例如数据一致性、事务处理等。
以下是一个示例代码,演示如何将文件存储在文件系统中,并在数据库中存储文件的元数据信息:
-- 创建存储文件元数据的表
CREATE TABLE documents (
id INT AUTO_INCREMENT PRIMARY KEY,
filename VARCHAR(255),
filepath VARCHAR(255),
size INT,
created_at DATETIME
);
-- 插入文件元数据信息
INSERT INTO documents (filename, filepath, size, created_at)
VALUES ('document.pdf', '/path/to/file/document.pdf', 1024, NOW());
-- 查询文件元数据
SELECT * FROM documents;
-- 从文件系统中检索文件
SELECT filepath FROM documents;
通过这种方法,我们可以充分利用文件系统的优势来存储和检索大文件,同时使用数据库来管理文件的元数据信息。这样可以避免使用BLOB存储大文件的劣势,并提高系统的性能和效率。
在将文件存储为数据库中的Blob对象时,可能会遇到一些问题。首先,与将文件存储在文件系统上相比,速度可能会受到影响。其次,缓存也可能成为一个问题。尽管数据库可以对静态内容进行缓存,但如果数据库还要处理其他各种查询,那么大型文档可能很快就会被清除缓存。此外,内存限制也可能成为一个挑战。在某些情况下,将大型文件读入内存可能会导致内存溢出错误。因此,在将文件存储为Blob对象时,需要谨慎考虑代码和内存使用情况。
为了解决这些问题,可以考虑以下解决方法。首先,在性能方面,可以将文件存储在文件系统上,而不是数据库中的Blob对象。这样可以提高访问速度,并减少数据库负载。其次,为了解决缓存问题,可以使用Web服务器的缓存功能。Web服务器对于静态内容的缓存效果可能更好。最后,在处理内存限制时,可以优化代码,避免将整个文件读入内存。可以使用流式传输的方式将文件发送给用户,以减少内存消耗。
如果文件较小且数据库负载不大,将文件存储为数据库中的Blob对象可能没有太大问题。但是,在面临性能、缓存和内存限制等问题时,需要谨慎考虑,并可能需要采取相应的解决措施。比如,可以考虑将文件存储在文件系统上,或者使用多个服务器来处理文件存储。
在数据库不断增大的过程中,备份变得越来越困难。恢复一个包含超过100GB数据的表的备份并不是一件令人愉快的事情。另外一个问题是,随着数据集的增长,所有表管理功能的速度越来越慢。
但是,通过将数据表设置为只包含两个字段(ID和BLOB),这个问题可以得到解决。而当你遇到备份数据集的瓶颈时,通过主键检索数据可能只会成为一个问题。
与任何大型数据集一样,可以使用一个服务器进行备份数据库的快照。对于BLOB数据,与其他任何BLOB数据相比并没有区别。然而,将BLOB数据移动到它自己的表中可以加快读取其他列的速度,因为BLOB数据不需要被引用/加载到内存中。此外,大多数网络开发中并没有大型的BLOB数据,除了图片。
在Oracle中,每个长度超过1000个字符的Unicode字符串都需要一个CLOB,因为Oracle使用4个字节存储Unicode,而每个值必须小于4k。很容易超出这个限制。我们需要使用CLOB来存储未解析的XML数据,而使用BLOB来存储证书。
将文档作为BLOB存储在数据库中的缺点主要是备份和恢复的困难,以及随着数据集增长,表管理功能的下降。然而,通过将数据表设置为只包含ID和BLOB两个字段,将BLOB数据移动到自己的表中,以及使用服务器进行快照备份,可以解决这些问题。此外,在Oracle中,需要注意Unicode字符串长度和使用CLOB和BLOB的情况。