2012-01-02 3 views
0

I 250,000レコードを含むデータベースを持っています。 DataReaderを使用してレコードをループし、ファイルにエクスポートします。 DataReaderWHEREという条件でレコードをループするだけで約22分かかります。私は2つのだけの列(idとその中の約1000文字でnvarchar(max)列)を選択しています。 22分には、SQL Server Expressのための正しいのSQL Server 2008 R2 ExpressのDataReaderの性能

を鳴らしていますか? 1GBのRAMまたは1CPUがこれに影響を与えますか?

+0

より多くのテスト - SQLServer 2008 R2のフルバージョンを同じデータベースにインストールした同じマシンにインストールしました。 DataReaderは、250,000レコードを4.3分でループし、22分をSQLExpressでループしました。 – econner

+0

あなたは〜1k文字にしかアクセスしていないと言いますが、実際のテーブルの大きさはどれくらいですか? 'exec sp_spaceused myTable'を実行します(' myTable'をテーブル名に置き換えてください)。 'NVARCHAR(MAX)'の単一レコードの最大サイズは非常に大きいので、 'NVARCHAR'フィールドにはインデックスを持たない/できないので、行全体を要求します。つまり、行あたり10KB、250k行は実際には2.5GBなどです。つまり、RAMにすべて収まるわけではありません。 – Seph

+0

行= 255,000。 reserved = 1994320 KB、data = 1911088 KB、index_size = 82752 KB、未使用480 KB – econner

答えて

0

22分(でも22秒は、私にはそのためにとても長い音)250K、レコードに対してSELECT(非凝集)1つの基本についてあまりにも長いですね。あなたには、いくつかのコードとあなたのスキーマ定義を投稿することができれば、なぜ、それが役立つだろうと言って

。トリガが設定されていますか?

各レコード(2KB)に1K文字を使用すると、SQL Expressの1GBの制限内に250Kレコード(500MB)が収まるはずです。あなたが見ているパフォーマンスの問題の

考えられる原因は次のとおりです。あなたが

  • 過度のディスク上の断片化を述べただけで2列よりもはるかに広い列を有する他のアプリケーション
  • から

    • 競合をテーブルまたはDB MDFファイルのいずれかのテーブル
    • あなたのアプリとDBのネットワーク接続が遅い

    更新:私は簡単なテストをしました。私のマシンでは、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(); 
          } 
         } 
        } 
    } 
    

    結果(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類似の結果。各列から「ヴァル」要素をキャプチャ

    は4093ミリ秒(string val = (string)reader["val"];)にExecutionTimeが増加しました。 DataTable.Load(reader)を使用すると約4600ミリ秒かかりました。

    SSMSで同じクエリを実行すると、すべての256K行を取得するのに約8秒かかりました。

  • +2

    +1ですが、 'SqlDataReader'も' using'ブロックに入れてください。 –

    +0

    datareaderループのフィールドから読み取った結果はどうなりますか?たとえば、文字列テスト= reader ["val"]。ToString(); – econner

    +0

    "val"フィールドを読み取ると、ExecutionTimeが4093 msに増加します。すべての結果行の取得を含む、SSMSからのクエリの実行には約8秒かかります。 – RickNZ

    0

    潜在的なヒントを提供exec sp_spaceused myTableを実行しているから、あなたの結果:NVARCHAR(MAX)をすることはできませんので、(インデックスが作成されていないフィールドを読み込むときにここで注意すべき重要なことは、あなたのテーブルを意味reserved = 1994320 KBある

    rows = 255,000 
    reserved = 1994320 KB 
    data = 1911088 KB 
    index_size = 82752 KB 
    unused 480KB 
    

    は、いくつかの1866メガバイトですインデックス付き)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つの解析しか行いません)、commentsVARCHAR(MAX)であり、 2GBのSQLは、テーブルをメモリにロードする必要があります。 comment_dateが索引付けされていない追加のフィールドである

    SELECT id, comments 
    FROM myTable 
    ORDER BY 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 ? " 
    
    +0

    id列はGuid型で、Pkに設定され、Pk用にクラスタ化されています。現時点では、WHERE条件またはORDER BY条件を設定するのではなく、SELECT *を実行して250,000レコードをすべてループします。私はあなたが提供した3つのコマンドを実行しています。また、私はテーブルから5000レコードを削除し、違いがあるかどうかを確認して結果を返信します – econner

    関連する問題