我有一个包含250,000条记录的数据库。我正在使用DataReader
来循环记录并导出到文件。只用DataReader
和WHERE
条件循环记录大约需要22分钟。我只选择了两列(id
和nvarchar(max)
列,其中包含约1000个字符)。SQL Server 2008 R2 Express DataReader性能
22分钟听起来对SQL Server Express是否正确? 1GB的RAM或1CPU会对此产生影响吗?
我有一个包含250,000条记录的数据库。我正在使用DataReader
来循环记录并导出到文件。只用DataReader
和WHERE
条件循环记录大约需要22分钟。我只选择了两列(id
和nvarchar(max)
列,其中包含约1000个字符)。SQL Server 2008 R2 Express DataReader性能
22分钟听起来对SQL Server Express是否正确? 1GB的RAM或1CPU会对此产生影响吗?
对于单个基本(非聚合)SELECT对250K记录(甚至22秒听起来对我而言非常长),22分钟听起来太长了。
要说明原因,如果您可以发布一些代码和架构定义,这将有所帮助。你有没有配置任何触发器?
对于每条记录(2KB)中的1K个字符,250K条记录(500MB)应该符合SQL Express的1GB限制,因此内存不应单独作为该查询的问题。
您遇到的性能问题的可能原因包括:
更新:我做了一个快速测试。在我的机器上,使用SqlDataReader读取250K 2KB行不到1秒。
首先,创建256K行测试表(这个只用了约30秒):
CREATE TABLE dbo.data (num int PRIMARY KEY, val nvarchar(max))
GO
DECLARE @txt nvarchar(max)
SET @txt = N'put 1000 characters here....'
INSERT dbo.data VALUES (1, @txt);
GO
INSERT dbo.data
SELECT num + (SELECT COUNT(*) FROM dbo.data), val FROM dbo.data
GO 18
测试网页读取数据并显示统计:
using System;
using System.Collections;
using System.Data.SqlClient;
using System.Text;
public partial class pages_default
{
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
using (SqlConnection conn = new SqlConnection(DAL.ConnectionString))
{
using (SqlCommand cmd = new SqlCommand("SELECT num, val FROM dbo.data", conn))
{
conn.Open();
conn.StatisticsEnabled = true;
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
}
}
StringBuilder result = new StringBuilder();
IDictionary stats = conn.RetrieveStatistics();
foreach (string key in stats.Keys)
{
result.Append(key);
result.Append(" = ");
result.Append(stats[key]);
result.Append("<br/>");
}
this.info.Text = result.ToString();
}
}
}
}
结果(ExecutionTime在毫秒):
IduRows = 0
Prepares = 0
PreparedExecs = 0
ConnectionTime = 930
SelectCount = 1
Transactions = 0
BytesSent = 88
NetworkServerTime = 0
SumResultSets = 1
BuffersReceived = 66324
BytesReceived = 530586745
UnpreparedExecs = 1
ServerRoundtrips = 1
IduCount = 0
BuffersSent = 1
ExecutionTime = 893
SelectRows = 262144
CursorOpens = 0
我用SQL Enterprise和SQL Express重复了测试,机智h类似的结果。
从每行中捕获“val”元素将ExecutionTime增加到4093 ms(string val = (string)reader["val"];
)。使用DataTable.Load(reader)
花了大约4600毫秒。
在SSMS中运行相同的查询需要大约8秒钟来捕获所有256K行。
你运行exec sp_spaceused myTable
结果提供了一个潜在的暗示:
rows = 255,000
reserved = 1994320 KB
data = 1911088 KB
index_size = 82752 KB
unused 480KB
这里要注意的重要一点是reserved = 1994320 KB
这意味着你的表是一些1866年MB,读书未索引(因为NVARCHAR(MAX)
字段时,不能索引)SQL Server必须在限制列之前将整行读入内存。因此,您可以轻松运行超过1GB RAM的限制。
作为一个简单的测试,删除最后(或第一个)150k行并再次尝试查询,看看您获得的性能。
几个问题:
id
场或别的东西)?`nvarchar(max)
字段?在最适合你的情况你的PK是id
,也是一个聚集索引,你要么没有order by
或者你是order by id
:
假设你varchar(max)
字段命名为comments
:
SELECT id, comments
FROM myTable
ORDER BY id
这将工作正常,但它会要求你读取所有行到内存(但它只会做一个解析表),因为comments
是VARCHAR(MAX)
,不能索引和表是2GB SQL然后将不得不将表加载到内存中的部分。
很有可能发生的事情是,你有这样的事情:
SELECT id, comments
FROM myTable
ORDER BY comment_date
凡comment_date
是一个额外的字段不被索引。在这种情况下,行为可能是SQL无法实际对内存中的所有行进行排序,并且最终不得不多次将表进行内存分页,导致出现问题。
在这种情况下,一个简单的解决方案是添加一个索引comment_date。
但是,假设你只有读访问数据库是不可能的,那么另一种解决方案是使数据的你想要一个本地临时表,可以使用下列内容:
DECLARE @T TABLE
(
id BIGINT,
comments NVARCHAR(MAX),
comment_date date
)
INSERT INTO @T SELECT id, comments, comment_date FROM myTable
SELECT id, comments
FROM @T
ORDER BY comment_date
如果这不帮助,然后需要额外的信息,您可以发布您的实际查询以及您的整个表格定义和索引是什么。
超越这一切的运行下面的还原备份重建索引和统计信息后,你可能只是从损坏的统计痛苦(这发生在你备份一个碎片化的数据库,然后将其恢复到一个新的实例):
EXEC [sp_MSforeachtable] @command1="RAISERROR('UPDATE STATISTICS(''?'') ...',10,1) WITH NOWAIT UPDATE STATISTICS ? "
EXEC [sp_MSforeachtable] @command1="RAISERROR('DBCC DBREINDEX(''?'') ...',10,1) WITH NOWAIT DBCC DBREINDEX('?')"
EXEC [sp_MSforeachtable] @command1="RAISERROR('UPDATE STATISTICS(''?'') ...',10,1) WITH NOWAIT UPDATE STATISTICS ? "
id列是类型Guid并设置为Pk并为Pk群集。此时我不设置WHERE条件或ORDER BY条件,而只是执行SELECT *并循环所有250,000条记录。我现在正在运行你提供的3个命令。此外,我还会从表中删除5000条记录,看看它是否有所作为,然后发回结果 – econner 2012-01-06 05:35:07
更多测试 - 在具有相同数据库的相同机器上安装完整版本的SQLServer 2008 R2。 DataReader在4.3分钟内循环了250,000条记录,而SQLExpress则是22分钟。 – econner 2012-01-02 07:04:23
你说你只能访问〜1k个字符,但实际表格有多大?运行'exec sp_spaceused myTable'(用你的表名替换'myTable')。单个NVARCHAR(MAX)记录的最大大小非常大,并且由于您不会在NVARCHAR字段的索引中存在索引,所以您将请求整行,因此如果存在另一列也就是说每行10KB,你的250k行实际上是2.5GB等等,这意味着它不能全部适合RAM。 – Seph 2012-01-04 10:39:10
rows = 255,000。保留= 1994320 KB,数据= 1911088 KB,index_size = 82752 KB,未使用480KB – econner 2012-01-04 17:37:15