从存储过程获取数据到DataTable时内存利用率高

问题描述 投票:0回答:1

我想处理数百万行并对其进行一些处理并将这些记录导出到 Excel 文件中。当我获取记录并将其填充到

DataTable
时,它使用了大量的内存 - 大约 8 到 10 GB。我的 SQL 查询结果包含大约 300 列。

我尝试过批处理,也尝试过

SqlDataReader
。无论是否采用批量方式,它占用的内存几乎相同,并且使用
SqlDataReader
后,它不会影响内存。下面是我当前的代码。有什么办法可以阻止这种高利用率吗?

批量获取10000行记录:

DataTable dt = new DataTable();

for (int i = 0; i <= 0; i++)
{
    int startRow = 1;
    int endRow = 10000;

    for (int j = 0; (startRow == 1 || dt.Rows.Count >= 10000); j++)
    {
        dt = null;
        dt = _dataService.SqlExecuteDT(data);
        startRow = startRow + 10000;
    }
}

调用存储过程、填充数据表的代码:

public static DataTable SqlExecuteDT(string spname, Dictionary<string, object> parameters, DBName dBName = DBName.DBCONN)
{
    using (SqlConnection conn = new SqlConnection(DBConnection.GetConnectionString(dBName)))
    {
        using (SqlCommand cmd = new SqlCommand(spname, conn))
        {
            cmd.CommandTimeout = Timeout;
            cmd.CommandType = System.Data.CommandType.StoredProcedure;

            if (parameters != null)
            {
                foreach (KeyValuePair<string, object> kvp in parameters)
                    cmd.Parameters.AddWithValue(kvp.Key, kvp.Value ?? DBNull.Value);
            }

            conn.Open();

            // Use a forward-only, read-only data reader for memory efficiency
            using (SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
            {
                // Retrieve column schema
                DataTable schemaTable = reader.GetSchemaTable();

                // Create DataTable to hold the data
                DataTable dataTable = new DataTable();

                // Add columns to DataTable based on schema
                foreach (DataRow row in schemaTable.Rows)
                {
                    string columnName = row["ColumnName"].ToString();
                    Type dataType = (Type)row["DataType"];
                    dataTable.Columns.Add(columnName, dataType);
                }

                // Populate DataTable with data
                while (reader.Read())
                {
                    DataRow dataRow = dataTable.NewRow();

                    for (int i = 0; i < reader.FieldCount; i++)
                    {
                        dataRow[i] = reader[i];
                    }

                    dataTable.Rows.Add(dataRow);
                }

                return dataTable;
            }
        }
    }
}
c# asp.net-core asp.net-core-webapi
1个回答
0
投票

您的

SqlExecuteDT
功能过于复杂。您需要的一切都可以通过
DataTable.Load
获得。

public static DataTable SqlExecuteDT(string spname, Dictionary<string, object?> parameters = null, DBName dBName = DBName.DBCONN)
{
    using var conn = new SqlConnection(DBConnection.GetConnectionString(dBName));
    using var cmd = new SqlCommand(spname, conn);
    cmd.CommandTimeout = Timeout;
    cmd.CommandType = System.Data.CommandType.StoredProcedure;

    if (parameters != null)
    {
        foreach (var kvp in parameters)
            cmd.Parameters.AddWithValue(kvp.Key, kvp.Value ?? DBNull.Value);
    }

    conn.Open();
    using SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess);

    var table = new DataTable();
    table.Load(reader);
    return reader;
}

那么你的外循环就完全没有意义了。为什么会有一个循环呢?应该只是:

var dt = _dataService.SqlExecuteDT(SomeProcName);
© www.soinside.com 2019 - 2024. All rights reserved.