【问题标题】:Storing Link to File in a Database在数据库中存储指向文件的链接
【发布时间】:2012-10-05 22:21:25
【问题描述】:

我正在创建一个数据库应用程序,它(除其他外)允许用户上传和下载文件。这些文件存储在文件服务器上,我已经使用 PHP 脚本设置了一个 Apache HTTP 服务器来处理(即上传和下载)文件。数据库只存储文件的链接,而不是文件本身。我的问题是:我应该如何组织文件服务器上的文件?

目前,我正在根据当前日期创建一个目录结构,并使用当前日期/时间(包括毫秒)的 MD5 哈希加上一些随机字符(即我添加“salt”)重命名文件:

\\yyyy\mm\dd\debb40da158040e4f3b93f9576840c07

这个(上图)是存储在数据库中的链接(当然,我也把真实的文件名存储在数据库中,这样当用户去下载文件时我可以重命名文件——用户从不见实际链接)。

我使用yyyy\mm\dd 作为目录结构以避免性能问题(我被告知同一目录中的很多文件会减慢速度)并且我用唯一的字符串重命名文件以避免用户上传时发生冲突具有相同名称的文件。

我想就在这种情况下处理文件存储的最佳方式获得其他意见。我已经看到一些开发人员保留文件名,但在文件信息表中附加(作为前缀)相应行的数据库 ID ---我看到了这种方法的一些优点,因为文件名是“人类可读的”并且如果数据库文件信息表被损坏或删除,您可以弄清楚这些文件是什么。

【问题讨论】:

  • 你是对的,有一个包含很多文件的目录可能是一个性能问题。您对每天可能收到多少文件有任何预测吗?使用 MD5 作为命名方案的原因是什么?是为了确保一个唯一的名称吗?如果可能的话,我希望使用一个至少提供有关文件的一些信息的名称,而不是如此不透明的名称(更不用说在测试期间难以键入或找到。)
  • @Marvo 感谢您的反馈。我预计不会每天上传很多文件(可能每天大约 50 个文件),但有些文件可能相当大(~150 MB)。我同意你关于使用 MD5 作为文件名的说法......它非常“不透明”......我这样做的原因是为了确保一个唯一的名称并减少链接名称的长度。
  • 文件量听起来不是问题。 (文件的实际大小与为什么一个非常完整的目录是一个问题无关。)在一个企业中,我们有一堆与帐户相关联的图像,这些图像存储在类似于您正在做的事情中。我们没有对它们进行足够的分区。如果有人在目录上执行“ls”,它会严重影响机器的性能(原因我不记得了),因为它获得了所有的名称。这与目录中文件条目的数量有关(我们有数千个。)
  • 您还可以探索应用程序中为您生成唯一名称的方法(或编写一个。)您也可以使用序列(在 Oracle 中)或 next-number-table 来生成唯一名称.
  • @Marvo 感谢您的所有 cmets...感谢您对我的问题感兴趣。

标签: database database-design fileserver file-organization


【解决方案1】:

如何使用时间戳(上传日期)作为第一级目录,文件内容的 md5 哈希作为第二级(文件内容的哈希确保文件是唯一的/名称独立的),上传时间戳作为第三级的结构怎么样(使您可以在不同时间上传同一文件的不同版本),并且文件的实际文件名位于第 4 级。 e.g. <date timestamp>/<md5 of file contents>/<timestamp>/<filename>

这样您的目录结构将包含以下信息:

  • 在特定日期上传的文件列表
  • 独立于文件名的唯一文件
  • 版本控制
  • 保持文件名无需即时更改

文件内容 md5 哈希的缺点是,如果您有非常大的文件,生成时会产生轻微的开销。

其他想法

  • 如果这是一个有很多用户每天上传文件的系统并且肯定会创建 365 个目录一年中的每一天,尽管当您在目录中有大于 10k 的条目列表时性能会下降(并且在基于服务器的操作系统中大于 100k 到几百万),所以这应该给您大约 25-30 年如果您只使用一个日期目录,则在注意到任何退化之前。

  • 我相信文件内容的哈希值是保证文件名独立性的方法,虽然计算内容的 md5 会增加一点开销,但与上传时间相比,它是微不足道的。例如。根据连接速度,上传 100 mb 文件需要 x 时间,上传后您只需使用 md5sum 即时计算文件内容,这将增加几秒钟(5-6 用于 100 mb 文件)到用户将感知到的上传时间。

  • 您可以进一步使用文件内容的 md5(假设您也将其存储在您的数据库中)作为签名来保护原始上传文件的真实性

  • 1234563否则,您最终会在给定日期的同一文件内容 md5 命名为 dir 下得到不同的文件名)。
  • 不知道为什么你会介意 md5 字符串的长度。它不会影响性能,并且 md5 非常普遍并且很好地支持用于其他目的(例如验证文件)。但是,如果您真的想缩短长度,请查看http://en.wikipedia.org/wiki/List_of_hash_functions 并选择 16 位或 8 位甚至 4 位 crc 进行试验(同样,这取决于您将如何使用它,文件内容或文件名和这些有多大)。

  • 1234563性能,当达到限制时,您将有一个脚本创建一个具有相同结构的新组。通过这种方式,您可以避免重复/相似的信息(日期、年份、月份、时间戳等),您可以自己控制可接受的限制,您可以让不同的用户上传相同的文件,您可以通过 filehash 来判断文件是否已被无论文件名如何上传,您都使用时间戳进行版本控制,并且在最后的目录中只有一个文件具有其原始(或指定)名称。如果您是 FaceBook 并拥有十亿用户,您可以拥有这种结构并跨不同服务器托管目录组集群。如果您有一个拥有 1000 个用户的小型网站,您甚至不需要群组位。

【讨论】:

  • @George_T 感谢您的回复。我不太确定将日期用作第一级目录,因为包含这些目录的目录会随着时间的推移而变得巨大(仅一年后将有 365 个目录!)另外,获取文件本身的 MD5 哈希是正如您提到的那样,出于性能原因,不可行。但是,我认为您可能会对使用 MD5 哈希(当前时间戳)作为 directory 名称(即使用目录命名方案,以确保目录保证仅包含 一个 文件)。
  • @George_T (上一条评论的继续...) 如果我们可以保证最低级别的目录只包含一个文件,那么我们可以简单地使用它的原始文件名保存文件。因此,总而言之,目录结构类似于\\yyyy\mm\dd\uniqueHash\originalFileName。另外,也许我可以为uniqueHash 使用比 MD5 更小的散列函数来最小化路径长度。
  • @HydroPowerDeveloper 谢谢,我已经根据您的 cmets 更新了答案
  • @George_T 感谢您的所有想法……它们都很棒。我将感谢您回答我的问题,因为我肯定会使用您的一些建议(例如,使用用户 ID 和探索更小的哈希函数)。作为记录,这是我计划使用的格式:\\<yyyy>\<mm>\<dd>\<userID>\<uniqueHash>\originalFileName
猜你喜欢
  • 2011-12-28
  • 2019-01-29
  • 1970-01-01
  • 1970-01-01
  • 2014-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-11
相关资源
最近更新 更多