代码之家  ›  专栏  ›  技术社区  ›  SqlRyan

当元数据在SQL数据库中时存储/检索数百万文件的最佳方法

  •  8
  • SqlRyan  · 技术社区  · 15 年前

    我有一个过程,最初将生成300-400万个PDF文件,并以每天80k的速度继续。它们每个都很小(50K),但我担心的是如何管理生成的文件总量,以便轻松查找。一些细节:

    1. 生成一个文件后,我将运行其他一些步骤,并且将有一些服务器参与,因此我需要在生成文件时监视这些文件。
    2. 一旦生成,这些文件将通过我编写的查找过程可用。基本上,我需要根据订单号提取它们,每个文件都是唯一的。
    3. 可以随时重新提交现有订单号,生成的文件需要覆盖原始副本。

    最初,我计划将这些文件全部写入NAS上的一个目录,但我意识到这可能不是一个好主意,因为它们有数百万个,Windows可能无法很好地处理一百万个文件查找。我在找一些建议:

    1. 一个文件夹可以吗?这些文件将永远不会被列出-它们只能使用我已经确定文件名的system.io.file进行检索。
    2. 如果我做一个文件夹,我能用system.io.directorywatcher监视新文件吗,即使有这么多文件,还是会开始对这么多文件变得迟钝?
    3. 应该将它们存储为SQL Server数据库中的blob吗?因为我需要用一个引用值来检索它们,也许这更有意义。

    谢谢你的想法!

    12 回复  |  直到 15 年前
        1
  •  3
  •   Philip Kelley    15 年前

    我将文件分组到特定的子文件夹中,并尝试以某种业务逻辑方式组织它们(子文件夹)。也许在某一天内所有的文件都是这样?每天6小时?或者每一个文件,我会说最多1000个(可能有一个理想的数字,希望有人会发布)。

    文件是否老化并被删除?如果是,则排序和文件是可删除的块。如果没有,我可以做你的硬件供应商吗?

    在数据库中存储文件的两边都有参数。

    • 一方面,您得到了增强的安全性,因为从数据库中提取文件更难;另一方面,您得到的性能可能更差,因为从数据库中提取文件更难。
    • 在数据库中,您不必担心每个文件夹、扇区、NAS集群有多少个文件,这是数据库的问题,可能它们有一个很好的实现。另一方面,管理/审查数据会比较困难,因为它在一张表中会出现无数的blob,而且,嗯,糟糕。(您可以根据前面提到的业务逻辑对表进行分区,这将使删除或存档变得非常容易执行。或者分区视图,因为表分区限制为1000个分区。)
    • SQL Server2008具有文件流数据类型;我对它不太了解,可能值得研究。

    最后要担心的一点是保持数据“一致”。如果数据库将信息与文件的路径/名称一起存储在文件上,并且文件被移动,则可能会完全被托管。

        2
  •  4
  •   Bravax    15 年前

    要回答您的问题:

    1. 我不会把它们放在一个文件夹里。因为你有可能 将要查看磁盘上的实际文件,而不是其他方式。
      相反,为什么不将它们存储在单独的目录中,分成1000个批次呢? 可能使用ID作为密钥。
    2. 许多文件可能会淹没DirectorWatcher,因此一些文件会丢失。 我以前用过这个,过了一段时间(几百年后),我发现它开始丢失文件。 可能对传入的文件使用不同的目录,然后每隔一段时间处理一次。 然后可以触发一个进程来更新原始文件。
    3. 我不会将文档存储在数据库中,而是将元数据存储在数据库中。
        3
  •  2
  •   Juergen Brendel    15 年前

    您可以轻松地将文件组织到多个文件夹中,而无需按照业务逻辑或每天的顺序来执行此操作,如果这种排序方式是“块状”(在一个文件夹中点击很多次,而在其他文件夹中点击很少),则这一点尤其好。

    最简单的方法是为文件名创建一个唯一的哈希,这样您可能会得到如下结果:

    sf394fgr90rtfofrpo98tx.pdf
    

    然后将其分成两个字符块,您将得到:

    sf/39/4f/gr/90/rt/fo/fr/po/98/tx.pdf
    

    如您所见,它为您提供了一个可以轻松导航的深目录树。

    有了一个好的散列函数,这将是非常均匀的分布,您将永远不会得到超过1296个条目每个目录。如果发生碰撞(应该非常罕见),只需在末尾添加一个数字:tx.pdf、tx_1.pdf、tx_2.pdf。同样,在如此大的散列上发生碰撞应该是非常罕见的,因此,由于这一点而产生的聚集是没有问题的。

    您说过文档是数字签名的,所以您可能在那里以签名字符串的形式拥有所需的哈希。

        4
  •  2
  •   Matthew    15 年前

    1)一个简单的文件夹使用一个单独的索引可能会很快被接受,但是把它放在子目录中是很简单的,这样你就可以浏览了。
    因此,现在您必须了解您的命名约定。虽然我通常会建议使用散列来获得均匀的ID分布,但是当你做了这么多事情时,使用已经得到的值可能是有意义的。如果你有订单号,你也有时间戳吗?如果是,只需在订单号前面加上时间戳。

    请注意,如果您使用的是订单ID,您可能会遇到 http://en.wikipedia.org/wiki/Benford%27s_law

        5
  •  1
  •   Beth    15 年前

    确定子目录的一些逻辑顺序,并将它们存储在一个文件夹中不超过512个左右文件的块中。

    不要将文件存储在数据库中。数据库用于数据,文件服务器用于文件。将它们存储在文件服务器上,但将路径和检索信息存储在数据库中。

        6
  •  1
  •   Will Hartung    15 年前

    你需要测试一下。所有这些解决方案都依赖于底层的文件系统。有些文件系统可以处理巨大的目录,有些不能。有些文件系统索引它们的目录,有些则不需要(这两点不一定相关)。

    将内容分解到目录树中有合理的执行机会,这仅仅是因为最终,单个目录往往只有很少的总体条目。这对大多数文件系统都有效,因为即使是对文件进行线性目录搜索的“愚蠢”文件系统也可以相当快地搜索几百个条目。

    如果文件系统正在为目录编制索引(例如,对btree进行索引,或只是对其进行内部排序,这在本文中实际上是相同的),那么目录大小就不那么重要了,尽管有些工具可能会抱怨(加载一个包含4米文件的Windows资源管理器窗口,谁知道会发生什么)。

    所以,我将研究您计划的操作系统和文件系统选项,并测试它,看看哪一个最适合您。

        7
  •  1
  •   ZeroCool    15 年前

    为什么不考虑在转换成PDF之后将所有这些文件存储到数据库(BLOB)中呢? 因此优势:

    1. 我相信你不必直接处理操作系统I/O,一切都由数据库决定。
    2. 无需散列命名
    3. 易于备份和维护
        8
  •  1
  •   Dan McClain    13 年前

    当使用数据库存储文件时,特别是使用小文件时,开销应该很小。 但是你也可以做如下的事情:

    DELETE FROM BLOBTABLE WHERE NAME LIKE '<whatever>'
    

    或者,当您有到期日期,或者想要刷新文件时,您可以通过以下方式将其删除:

    DELETE FROM BLOBTABLE WHERE CREATIONDATE < ...
    etc...
    
        9
  •  0
  •   Mark Redman    15 年前

    问题:

    为什么这些文档需要生成并存储为PDF?

    如果可以生成它们,为什么不将数据保存在数据库中,并在需要时动态生成它们呢?这意味着您可以搜索搜索所需的实际数据,而不必将文件放在磁盘上。这样,您还可以在需要时更新PDF模板,而无需重新生成任何内容?

        10
  •  0
  •   NTDLS    15 年前

    1) 这与我通常所说的完全相反,但您可能希望将它们存储在SQL数据库中,因为它们实际上是很小的文件。SQL Server还允许您快速、轻松地找到所需的文件,而不需要任何与枚举如此大的目录相关联的疯狂磁盘破坏。 此外,将文件存储在SQL中(虽然我通常是针对SQL的),将大大简化备份/恢复过程。

    2) 将它们全部存储在目录中,并使用Windows索引服务对它们进行索引( 颤抖 )或者在SQL Server中创建自己的索引,该索引将包含文件名和完整路径。我建议将它们存储在单独的目录中,每个目录只有数万个文件。也许您可以使用订购年份作为文件夹名?

    不管他们如何储存 不扫描目录以查找文件 -你肯定需要某种索引。

    希望这有帮助!

        11
  •  0
  •   Pyrolistical    15 年前

    我的文件数据库包含400多万个文件夹,每个文件夹中有许多文件。

    只是把所有文件夹都扔到一个目录中。NTFS可以毫无问题地处理这个问题,而像robocopy这样的高级工具可以在您需要移动它时提供帮助。

    只需确保您可以在不扫描的情况下索引文件。我通过在MySQL数据库中抛出索引来实现这一点。

    因此,为了得到一个文件,我在mysql数据库中搜索一些元数据并获取一个索引。然后我使用这个索引直接读取文件。到目前为止,我的比例很高。但请注意,您将把所有内容都转换成随机访问,从而实现随机读/写。这对于HDD来说性能很差,但幸运的是,SSD将有很大帮助。

    另外,我不会将文件丢到MySQL数据库中。如果没有了解MySQL的客户机,您将无法进行网络读取。现在我可以使用任何程序通过网络访问任何文件,因为我只能使用其网络URL。

        12
  •  0
  •   mcauthorn    15 年前

    我想就像其他很多人说的那样,你应该做子文件夹,但是你可以通过代码找到数据。例如,如果datetime有效,请使用它。从阅读你所说的内容来看,报告(每日、每周、每日x报告、每小时y报告等)似乎存在某种形式的层次结构,我将研究报告生成的时间和原因的结构,并以此方式建立我的目录。