我有一個包含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