250,000 レコードを含むデータベースがあります。を使用しDataReader
てレコードをループし、ファイルにエクスポートしています。DataReader
条件なしでレコードをループするだけで、WHERE
約 22 分かかります。id
2 つの列 (およびnvarchar(max)
約 1000 文字の列) のみを選択しています。
SQL Server Express の場合、22 分は正しく聞こえますか? 1GB の RAM または 1CPU はこれに影響しますか?
250,000 レコードを含むデータベースがあります。を使用しDataReader
てレコードをループし、ファイルにエクスポートしています。DataReader
条件なしでレコードをループするだけで、WHERE
約 22 分かかります。id
2 つの列 (およびnvarchar(max)
約 1000 文字の列) のみを選択しています。
SQL Server Express の場合、22 分は正しく聞こえますか? 1GB の RAM または 1CPU はこれに影響しますか?
250,000 件のレコードに対して 1 つの基本的な (非集計) SELECT を実行するには、22 分は長すぎるように思えます (22 秒でも、私には非常に長く聞こえます)。
理由を言うと、コードとスキーマ定義を投稿していただけると助かります。トリガーが構成されていますか?
各レコード (2KB) に 1,000 文字の場合、250,000 件のレコード (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
Web ページをテストしてデータを読み取り、統計を表示します。
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();
}
}
}
}
結果 (ミリ秒単位の実行時間):
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 でテストを繰り返したところ、同様の結果が得られました。
各行から「val」要素をキャプチャすると、ExecutionTime が 4093 ミリ秒に増加しました ( string val = (string)reader["val"];
)。使用DataTable.Load(reader)
には約4600ミリ秒かかりました。
SSMS で同じクエリを実行すると、256K 行すべてをキャプチャするのに約 8 秒かかりました。
ランニングの結果は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
これは正常に機能しますが、すべての行をメモリに読み込む必要があります (ただし、テーブルに対して 1 つの解析のみを実行します)。これ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 ? "