我有一个包含大量日期/时间戳记记录的数据库。我需要遍历这些记录(按时间顺序)并对它们进行一些分析。
数据库太大,无法一次拉入每条记录,所以我想一次拉几周/天/小时/等。我遇到的问题是,无论我尝试过什么,数据库(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
感谢。
答案 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
请注意 SqlConnection
,SqlCommand
和SqlDataReader
实现IDisposable
,因此您通常希望将它们包装在{{1}中}。clause。
答案 1 :(得分:2)
Filip的回答是正确的,这就是SQL Server的行为方式。
默认的原因通常是数据库服务器在专用计算机上运行,该计算机除数据库外几乎没有运行,#1问题是数据库速度。您通常希望尽可能多地保留在内存中,以便最大限度地减少磁盘所需的频率。
以编程方式配置设置的替代方法,您可以使用Sql Server Management Studio(SSMS)更改配置。连接到您的数据库,右键单击它并转到“属性”。在“内存”页面中,您可以配置数据库将使用的最大内存。
答案 2 :(得分:1)
SqlDataReader
将流式传输结果。只要您不保留读取器记录返回的数据,.NET垃圾收集器就会收集所有数据(在不确定的时间)。换句话说,您的while(reader.Read()) ProcessRecord(reader);
会正常工作。 .NET不会将整个集合加载到内存中(除非您明确地这样做,例如使用DataSet
或DataTable
)。