2016-07-27 22 views
1

私は、今の私が唯一、最新の10人の顧客を必要としますSqlDataReaderのを使用してデータを読み取り、収量はIEnumerableを返すメソッドを、例えば:Take(10)とSqlDataReaderのTOP 10?

IEnumerable<string> LoadCustomers() 
{ 
using(SqlDataReader rdr = cmd.ExecuteReader()) 
{ 
    while (rdr.Read()) 
    { 
     yield return rdr.GetString(0); 
    } 
} 
} 

を持っています。私はthis postによると、全体の結果セットは、DataReaderオブジェクトを読み込む場合でも、クライアントにSQL Serverから送信されている

SELECT TOP 10 FROM Customers ORDER BY CreationDate DESC 

LoadCustomers.Take(10) 

またはSQLへのパラメータとして10を渡すのか、私のSQLを作ることができますわずか数行(接続が開いている限り) - 私はTake(10)アプローチを回避する必要があります。その余分なデータがクライアントに送信されるか、回避するための時期尚早な最適化が行われるからです(yield return codeは、それは10行を読み取った後、データ伝送は停止します)。

+2

「ORDER BY CreationDate DESC'? – jarlh

+4

時期尚早の最適化ではありません。実際に必要なものだけをデータベースから取り出します。 10人だけ必要なときに10,000人の顧客を選択するのは意味がありません。 –

+1

あなたは、その投稿が言っていることを誤解しています。読み込みを停止すると、結果セット全体がクライアントに送信されませんが、一部の行はすでにバッファされている可能性があります。 'SqlDataReader'はネットワークを越えて先読みしません。たいていの場合、 'TOP(10)'をデータベースサーバに送信したい理由とそれが早すぎる最適化ではない理由は、オプティマイザは、テーブル全体を読み込みます(他に何もない場合、クエリはあらかじめメモリを少なく割り当てます)。 –

答えて

2

最適化があるかどうかので、 「時期尚早」は主観的なものであり、私はこの質問を「DataReader 10行がクエリでTOP(10)を使用するのと同じパフォーマンス特性を持つと、読み込みを停止しますか?

答えはいいえです。サーバーにTOP(10)を渡すと、オプティマイザは、問合せが戻す(この場合は読取りも)最大で10行であるという知識を使用して、読込み、メモリー付与、I/Oバッファ、ロックの細分性および並列性を調整できます。あなたが実際に前に停止しているかどうかにかかわらず、クライアントがすべての行を読み込んでいる場合に備えて、TOPから出発する必要があります。

読んでいるかどうかにかかわらず、サーバーが行を送信することは正しくありません。 SqlDataReaderで行を引くことは、概念的には行ごとの操作です。Reader.MoveNextを発行すると、サーバーから次の行だけを取り出し、その行だけをフェッチします。しかし、パフォーマンスの観点から、行は要求する前にバッファリングされています(両方ともサーバーのネットワークバッファ内にあります)。したがって、最初の.MoveNextコールの後で、たとえそのうちの10個だけを読み込んだとしても、バッファに取り込まれた100行で終わる可能性があります。

オーバーヘッドに関しては、これらのバッファは最終的には固定サイズなので、これは私の主な懸念事項ではありません。サーバーはいくつの行があるかにかかわらず結果セットのすべての行をバッファリングせずにバッファリングしません(これは非常に非効率的です一般に)。 10行しか読んでいない場合、クエリが最終的に1,000行または1,000,000行を返すかどうかは、バッファリングの点では問題になりませんが、主にクエリプランの観点からは問題になりません。それにもかかわらず、オーバーヘッドに追加されます。

1

また、改ページスキップ(0)とテイク(10)を柔軟に使用することもできます。 SQL 2012で

SQL Server 2012の

SELECT name, 
     CreationDate   
    FROM customer 
ORDER BY 
     CreationDate  
OFFSET @skip ROWS 
FETCH NEXT @take ROWS ONLY; 

SQL 2005

SET @take = (@skip + @take) 

;WITH customer_page_cte AS 
(SELECT 
     name, 
     CreationDate, 
     ROW_NUMBER() OVER (ORDER BY CreationDate desc) AS RowNumber 
FROM customer 
) 

SELECT name, 
     CreationDate 
    FROM customer_page_cte 
WHERE RowNumber > @skip AND RowNumber <= @take 

2008のC# - コマンドのストアドプロシージャを使用:)

var command = @"SELECT name, 
         CreationDate   
        FROM customer 
       ORDER BY 
         CreationDate  
       OFFSET @skip ROWS 
       FETCH NEXT @take ROWS ONLY;"; 

      using (var conn = new SqlConnection("Data Source=.;Initial Catalog=Stackoverflow;Integrated Security=True")) 
      { 
       conn.Open(); 
       using (var cmd = new SqlCommand(command, conn)) 
       { 
        cmd.Parameters.AddWithValue("skip", 0); 
        cmd.Parameters.AddWithValue("take", 10); 

        var reader = cmd.ExecuteReader(); 
        while (reader.Read()) 
        { 
         Console.WriteLine(reader.GetString(0)); 
        } 
       } 
      } 
関連する問題