c# - 验证网络上 3.5 亿个文件的存在

标签 c# .net sql-server tsql

我有一个包含大约 300,000,000 个绝对 UNC 路径的 SQL Server 表,我正在尝试(快速)验证每个路径以确保 SQL Server 表中的路径确实作为磁盘上的文件存在。

从表面上看,我正在以 50,000 个批处理查询表并递增一个计数器来推进我的批处理。

然后,我使用数据读取器对象来存储我当前的批处理集并遍历批处理,使用 File.Exists(path) 命令检查每个文件,如下例所示.

问题是,我正在处理大约。在四核 3.4ghz i5 和 16gb ram 上每秒最多 1000 个文件,这将需要几天时间。有更快的方法吗?

我在 SQL Server 表上确实有一个列存储索引,并且我已经对它进行了概要分析。我在 <1 秒内获得了 50k 条记录的批处理,因此在向 .net 控制台应用程序发出批处理时,这不是 SQL 瓶颈。

while (counter <= MaxRowNum)
{
    command.CommandText = "SELECT id, dbname, location FROM table where ID BETWEEN " + counter + " AND " + (counter+50000).ToString();

    connection.Open();

    using (var reader = command.ExecuteReader())
    {
        var indexOfColumn1 = reader.GetOrdinal("ID");
        var indexOfColumn2 = reader.GetOrdinal("dbname");
        var indexOfColumn3 = reader.GetOrdinal("location");

        while (reader.Read())
        {
            var ID = reader.GetValue(indexOfColumn1);
            var DBName = reader.GetValue(indexOfColumn2);
            var Location = reader.GetValue(indexOfColumn3);

            if (!File.Exists(@Location.ToString()))
            {
                //log entry to logging table
            }
        }
    }

    // increment counter to grab next batch
    counter += 50000;

    // report on progress, I realize this might be off and should be incremented based on ID
    Console.WriteLine("Last Record Processed: " + counter.ToString());
    connection.Close();
}

Console.WriteLine("Done");
Console.Read();

编辑:添加一些附加信息:

考虑通过数据库本身来完成这一切;它是具有 2tb 内存和 64 个内核的 sql server enterprise。问题是 sql server 服务帐户无权访问托管数据的 nas 路径,因此我的 cmdshell 通过 SP 运行失败(我不控制 AD 的东西),并且 UNC 路径有数十万个单独的子基于文件的 MD5 哈希的目录。所以枚举目录的内容最终是没有用的,因为你可能有一个文件 10 个目录深处只有 1 个文件。这就是为什么我必须进行文字完整路径匹配/检查的原因。

哦,一般来说路径很长。在我意识到这相当于 90gb 的数据之前,我实际上尝试将它们全部加载到内存中的列表中(哈哈,糟糕)。完全同意其他关于线程化的评论。数据库 super 快,完全不担心那里。虽然没有考虑 SMB 喋喋不休,但这很可能就是我遇到的问题。 – JRats 13 小时前

哦!如果文件不存在,我也只会更新数据库。如果是这样,我不在乎。所以我的数据库运行被最小化为抓取一批路径。基本上,我们将一堆数据从较慢的存储迁移到这个灵活的设备上,我被要求通过写一些东西来验证每个文件是否存在,以确保一切都真正完成了。

线程帮助很大。我将文件检查跨越 4 个线程,使我的处理能力达到了大约 3,300 条记录/秒,这要好得多,但如果可以的话,我仍然希望能更快。有什么好方法可以判断我是否受到 SMB 流量的限制?我注意到,一旦我尝试将线程数增加到 4 或 5,我的速度就会下降到涓涓细流;我想也许我在某个地方陷入僵局,但没有。

哦,由于您所说的确切原因,我无法执行 FilesOnNetwork 检查,与我要检查的文件相比,实际托管在那里的文件数量是其 3 或 4 倍。那个灵活的设备上可能有 1.5b 左右的文件。

最佳答案

优化 SQL 端在这里没有实际意义,因为您受文件 IO 限制。

我会使用 Directory.EnumerateFiles 来获取所有存在文件的列表。枚举目录中的文件应该比单独测试每个文件快得多。

您甚至可以完全反转问题并将该文件列表批量插入到数据库临时表中,这样您就可以直接在数据库中执行基于 SQL 的集合处理。

如果您想继续进行单独测试,您可能应该并行进行。目前尚不清楚该进程是否真的受磁盘限制。可能受网络或 CPU 限制。

并行性将通过重叠多个请求来提供帮助。问题可能出在网络延迟上,而不是带宽上。在 DOP 1,至少有一台机器在任何给定时间处于空闲状态。有时两者都是空闲的。


there's 3 or 4x as many files actually hosted there compared to what I want to check

使用 dir/b 命令将所有文件名的列表通过管道传输到 .txt 文件中。在有文件的机器上本地执行,但如果不可能远程执行。然后使用 bcp 将它们批量插入到数据库的表中。然后,您可以在高度优化的单个 SQL 查询中进行快速存在性检查。您将获得哈希连接。

如果你想并行执行此策略的 dir 阶段,你可以为此编写一个程序。但也许没有必要,尽管 dir 是单线程的,但它已经足够快了。

关于c# - 验证网络上 3.5 亿个文件的存在,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34104575/

相关文章:

c# - 从点和关系形成三角形

c# - 在 C# 5 中表示异步序列

c# - 使用RegEx每4个字符添加空格

c# - 我在哪里可以找到 .NET 中的 "clamp"函数?

c# - 基于参数锁定

sql - 如果其列包含列表中的任何值,则从结果中排除

c# - 为什么在同一 (UI) 线程中顺序调用 AsyncLock 的方式与不同线程的方式不同(例如通过 Task.Run)?

c# - Gtk.ListStore 中的虚拟模式?

c# - .net 线程安全的多次点击按钮

asp.net - 数据库字符串字段类型 : should it be nullable?