【问题标题】:Efficient way to load thousands of data from database and process it从数据库加载数千个数据并进行处理的有效方法
【发布时间】:2016-01-17 04:21:47
【问题描述】:

我在 Sql Server 2008 中有一个名为 PhotoStorages 的表,其中包含以下列。此表包含 5000 条数据。

PhotoStorageId              bigint
Photo                       image

目前我正在使用 C# 加载数据,如下所示

string sql = "SELECT * FROM PhotoStorages";
using (SqlCommand sqlCommand = new SqlCommand(sql))
{
    using (SqlDataAdapter dataAdapter = new SqlDataAdapter(sqlCommand))
    {
        using (DataTable dataTable = new DataTable())
        {
            dataAdapter.Fill(dataTable);

            if (dataTable.Rows.Count > 0)
            {
                for (int i = 0; i < dataTable.Rows.Count; i++)
                {
                    /*Resize the image and again update those resized image to the same database table*/
                }
            }
        }
    }
}

现在这个过程的执行速度很慢。我想知道是否有任何替代方法可以实现这一目标。提前致谢!

【问题讨论】:

  • 我其实认为调整图像大小的代码是最重要的!请为我们添加!
  • 很可能 99% 的缓慢过程发生在您已注释掉的部分。从数据库加载 5000 行可能只需要几毫秒。 SQL 连接只需要几毫秒,而且很少。因此,我建议您发布调整大小代码的内容。
  • @JamesHay 我认为如果您获得 5000 行包含字节树数据的行,它不会花费几毫秒...
  • @JamesHay:照片列包含大尺寸的图像。所以需要更多的时间。在 sql server 本身中,执行 select 查询需要 10 多分钟。
  • 你这里真的需要数据适配器和数据表吗,我认为在你的情况下使用简单的数据阅读器将是完美的。

标签: c# datatable


【解决方案1】:

您可以使用 SQL Server 中的 ROW_NUMBER 函数将查询分成更小的块,以便对结果进行分页。

我基于这个问题的答案: Paginate rows from SQL

首先,您必须将查询转换为执行分页的查询:

string sql = @"SELECT
                *
              FROM
                (
                    SELECT
                        ROW_NUMBER() OVER(ORDER BY Id DESC) AS RowNumber,
                        *
                    FROM
                        PhotoStorages
                ) AS T
              WHERE
                RowNumber BETWEEN @start AND @start + @pageSize";

您应该更改 ORDER BY Id 以匹配查询的实际 ID 列。在您的特定情况下,您可以使用表中的任何列,因为您正在使用所有数据,您无需担心返回的订单。 5000 行在宏伟的计划中并不大,但如果它是一个 100,000+ 行的大表,你会想要使用一个有索引的列。并且不要使用二进制数据列。

然后您可以在循环中运行您的查询:

var pageSize = 10;
var startAt = 0;

while(true) 
{
    using (SqlCommand sqlCommand = new SqlCommand(sql))
    {
        sqlCommand.Parameters.Add("@start", SqlDbType.Int).Value = startAt;
        sqlCommand.Parameters.Add("@pageSize", SqlDbType.Int).Value = pageSize;

        using (SqlDataAdapter dataAdapter = new SqlDataAdapter(sqlCommand))
        {
            using (DataTable dataTable = new DataTable())
            {
                dataAdapter.Fill(dataTable);

                var rowCount = dataTable.Rows.Count;
                var startAt = startAt + rowCount;

                if (dataTable.Rows.Count > 0)
                {
                    for (int i = 0; i < dataTable.Rows.Count; i++)
                    {
                        /*Resize the image and again update those resized image to the same database table*/
                    }
                }
                else 
                {
                    break;
                }
            }
        }
    }
}

这个想法是选择一定数量的行(我们通过pageSize 变量提供。然后我们对这些行进行调整大小,并继续循环。循环将继续,直到查询没有返回任何行。您为pageSize 使用的值取决于您,但例如,如果您有 2GB 的可用内存,并且每张照片为 2MB,如果您的 pageSize 为 1000 行,您将非常粗略地使用所有内存。您想使用大大少于所有可用内存,因为这不仅会减慢此进程,还会减慢机器上发生的所有其他需要可用内存的进程。

我的 C# 技能非常生疏,但希望这对你有用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-18
    • 2018-01-27
    相关资源
    最近更新 更多