数据库表的低内存遍历

时间:2012-03-20 15:13:21

标签: c# performance sql-server-2008

我有一个包含大量日期/时间戳记记录的数据库。我需要遍历这些记录(按时间顺序)并对它们进行一些分析。

数据库太大,无法一次拉入每条记录,所以我想一次拉几周/天/小时/等。我遇到的问题是,无论我尝试过什么,数据库(SQL Server)只使用​​我机器上的所有内存。即使应用程序关闭后,sqlservr.exe仍在使用我的所有内存。它通常使用大约1.8 GB的内存,无论我的“批次”只包含10条记录还是1,000,000条。

问题是:我如何查询数据库以一次获取“批次”记录,而数据库不会消耗每一点内存?

我正在使用System.Data.SqlClient库。这是一些伪代码:

String file = "C:\\db.mdf";
String connString = @"Data Source=.\SQLExpress;AttachDbFilename="C:\db.mdf";Integrated Security=True;User Instance=True";

SqlConnection conn = new SqlConnection(connString);
conn.Open();

DateTime start = DateTime.MinValue;
DateTime end = DateTime.MaxValue;

while()
{
   // This should query for 1 hour at a time (but I should be able to change the time interval)
   // I would like for the memory usage to be proportional to the time interval

   String query = "SELECT * From MyTable WHERE Date BETWEEN '" + start.ToString() + "' AND '" + end.ToString() + "'";
   SqlCommand cmd = new SqlCommand(query, conn);
   SqlDataReader reader = command.ExecuteReader();

   while(reader.Read())
      ProcessRecord(ref reader);

   start = end;
   end = end.AddHours(1);
}

conn.Close();

C#
.NET 3.5
SQL Server 2008

感谢。

3 个答案:

答案 0 :(得分:4)

这是正常的,SQL Server将使用所有可用内存unless configured differently

当您的其他应用程序请求更多时,Sql Server Express将释放内存,但它会尝试使用它可以缓存查询计划和数据的所有内存。

来自链接文章的引用:

  

以下示例将max server memory选项设置为4 GB:

 exec sp_configure 'show advanced options', 1; 
 GO 
 RECONFIGURE; 
 GO
 exec sp_configure 'max server memory', 4096; 
 GO 
 RECONFIGURE; 
 GO
 exec sp_configure 'show advanced options', 0;
 RECONFIGURE;  
 GO 

请注意 SqlConnectionSqlCommandSqlDataReader实现IDisposable,因此您通常希望将它们包装在{{1}中}。clause。

答案 1 :(得分:2)

Filip的回答是正确的,这就是SQL Server的行为方式。

默认的原因通常是数据库服务器在专用计算机上运行,​​该计算机除数据库外几乎没有运行,#1问题是数据库速度。您通常希望尽可能多地保留在内存中,以便最大限度地减少磁盘所需的频率。

以编程方式配置设置的替代方法,您可以使用Sql Server Management Studio(SSMS)更改配置。连接到您的数据库,右键单击它并转到“属性”。在“内存”页面中,您可以配置数据库将使用的最大内存。

答案 2 :(得分:1)

SqlDataReader将流式传输结果。只要您不保留读取器记录返回的数据,.NET垃圾收集器就会收集所有数据(在不确定的时间)。换句话说,您的while(reader.Read()) ProcessRecord(reader);会正常工作。 .NET不会将整个集合加载到内存中(除非您明确地这样做,例如使用DataSetDataTable)。