我想处理数百万行并对其进行一些处理并将这些记录导出到 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;
}
}
}
}
您的
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);