2016-12-08 9 views
3

DapperとADO.NETとDapperのマテリアライズタイムを比較しています。 最終的に、DapperはADO.NETよりも高速になりますが、最初にフェッチクエリを実行するとADO.NETよりも遅くなります。いくつかの結果は、DapperがADO.NETよりも少し速いことを示しています(ほぼすべての結果が同等ですが)。
SqlDataReaderの結果をオブジェクトにマップするのに非効率的なアプローチを使用していると思います。
これは、私がNULL可能列にキャストするasキーワードを使用し、私のコードSqlDataReaderの結果をオブジェクトにマップする最速の方法

var sql = "SELECT * FROM Sales.SalesOrderHeader WHERE SalesOrderID = @Id"; 
     var conn = new SqlConnection(ConnectionString); 
     var stopWatch = new Stopwatch(); 

     try 
     { 
      conn.Open(); 
      var sqlCmd = new SqlCommand(sql, conn); 

      for (var i = 0; i < keys.GetLength(0); i++) 
      { 
       for (var r = 0; r < keys.GetLength(1); r++) 
       { 
        stopWatch.Restart(); 
        sqlCmd.Parameters.Clear(); 
        sqlCmd.Parameters.AddWithValue("@Id", keys[i, r]); 
        var reader = await sqlCmd.ExecuteReaderAsync(); 
        SalesOrderHeaderSQLserver salesOrderHeader = null; 

        while (await reader.ReadAsync()) 
        { 
         salesOrderHeader = new SalesOrderHeaderSQLserver(); 
         salesOrderHeader.SalesOrderId = (int)reader["SalesOrderId"]; 
         salesOrderHeader.SalesOrderNumber = reader["SalesOrderNumber"] as string; 
         salesOrderHeader.AccountNumber = reader["AccountNumber"] as string; 
         salesOrderHeader.BillToAddressID = (int)reader["BillToAddressID"]; 
         salesOrderHeader.TotalDue = (decimal)reader["TotalDue"]; 
         salesOrderHeader.Comment = reader["Comment"] as string; 
         salesOrderHeader.DueDate = (DateTime)reader["DueDate"]; 
         salesOrderHeader.CurrencyRateID = reader["CurrencyRateID"] as int?; 
         salesOrderHeader.CustomerID = (int)reader["CustomerID"]; 
         salesOrderHeader.SalesPersonID = reader["SalesPersonID"] as int?; 
         salesOrderHeader.CreditCardApprovalCode = reader["CreditCardApprovalCode"] as string; 
         salesOrderHeader.ShipDate = reader["ShipDate"] as DateTime?; 
         salesOrderHeader.Freight = (decimal)reader["Freight"]; 
         salesOrderHeader.ModifiedDate = (DateTime)reader["ModifiedDate"]; 
         salesOrderHeader.OrderDate = (DateTime)reader["OrderDate"]; 
         salesOrderHeader.TerritoryID = reader["TerritoryID"] as int?; 
         salesOrderHeader.CreditCardID = reader["CreditCardID"] as int?; 
         salesOrderHeader.OnlineOrderFlag = (bool)reader["OnlineOrderFlag"]; 
         salesOrderHeader.PurchaseOrderNumber = reader["PurchaseOrderNumber"] as string; 
         salesOrderHeader.RevisionNumber = (byte)reader["RevisionNumber"]; 
         salesOrderHeader.Rowguid = (Guid)reader["Rowguid"]; 
         salesOrderHeader.ShipMethodID = (int)reader["ShipMethodID"]; 
         salesOrderHeader.ShipToAddressID = (int)reader["ShipToAddressID"]; 
         salesOrderHeader.Status = (byte)reader["Status"]; 
         salesOrderHeader.SubTotal = (decimal)reader["SubTotal"]; 
         salesOrderHeader.TaxAmt = (decimal)reader["TaxAmt"]; 
        } 

        stopWatch.Stop(); 
        reader.Close(); 
        await PrintTestFindByPKReport(stopWatch.ElapsedMilliseconds, salesOrderHeader.SalesOrderId.ToString()); 
       } 

であることが正しいのですか?
これはDapperのコードです。

using (var conn = new SqlConnection(ConnectionString)) 
     { 
      conn.Open(); 
      var stopWatch = new Stopwatch(); 

      for (var i = 0; i < keys.GetLength(0); i++) 
      { 
       for (var r = 0; r < keys.GetLength(1); r++) 
       { 
        stopWatch.Restart(); 
        var result = (await conn.QueryAsync<SalesOrderHeader>("SELECT * FROM Sales.SalesOrderHeader WHERE SalesOrderID = @Id", new { Id = keys[i, r] })).FirstOrDefault(); 
        stopWatch.Stop(); 
        await PrintTestFindByPKReport(stopWatch.ElapsedMilliseconds, result.ToString()); 
       } 
      } 
     } 
+0

非同期コードを削除して比較するとどうなりますか? –

+3

"最終的に、DapperはADO.NETよりも高速になりがちです" - 文章は計算されません。 Dapperは** ADO.NETの上に**座っています。それは消費するものよりも速い*ことはできませんし、ADO.NET *はあなたが行っているサービスを提供していません。 –

+0

あなたの主な問題は、あなたがたくさんの質問をしていることです。 INNER JOINまたは複数のSELECT( '。QueryMultiple')を使用して、複数のクエリを実行するのではなく、** 1つの**クエリですべてを行いますか? –

答えて

0

ここでは、ADO.NETコードを高速化する方法を示します。

selectを実行するときに、select *を使用するのではなく、選択しているフィールドを一覧表示します。これにより、データベース内でその注文が変更されても、フィールドが返ってくる順序を確実にすることができます。そのフィールドをReaderから取得するときは、名前ではなくインデックスで取得します。使用するとインデックスが速くなります。

また、強力なビジネス上の理由がない限り、文字列データベースフィールドをNULL値にできないようにすることをお勧めします。値がない場合は、空の文字列をデータベースに格納してください。最後に、DataReaderGetメソッドを使用することをお勧めします。これにより、フィールドに型を渡して、コードにキャストを必要としないようにします。ですから、例えば代わり​​にint型を使用DataReader.GetInt(index++)

としてDataReader[index++]値をキャストするためにしたがって、たとえば、このコード:

salesOrderHeader = new SalesOrderHeaderSQLserver(); 
salesOrderHeader.SalesOrderId = (int)reader["SalesOrderId"]; 
salesOrderHeader.SalesOrderNumber =  reader["SalesOrderNumber"] as string; 
salesOrderHeader.AccountNumber = reader["AccountNumber"] as string; 

int index = 0; 
salesOrderHeader = new SalesOrderHeaderSQLserver(); 
salesOrderHeader.SalesOrderId = reader.GetInt(index++); 
salesOrderHeader.SalesOrderNumber = reader.GetString(index++); 
salesOrderHeader.AccountNumber = reader.GetString(index++); 

なり見旋回とは、今それがためにないことを与えます君は。

+0

ありがとうございます。私はすべての列名をリストし、XDを取る 'GetXXX'メソッドを使用するのは怠惰ですが、プロパティにマップするとエラーになりやすいです。しかし、それが速ければ、私は試してみます。あなたは文字列フィールドがnullableであってはならないことを説明できますか? – witoong623

+0

多分、パフォーマンスの高いコードが必要な場所でのみ行う価値があります。 –

+0

テストの結果を報告するだけで、列の位置によって値が取得されるのが列の名前よりも速いため、コード生成ツールを使用してコードを生成することができます。私の場合、1ミリ秒も速くなります。ただし、ADO.NETはDapperよりも遅くはなく、DapperはADO.NETに匹敵します。 – witoong623

1

DBやリフレクションに疑問があるときは、「Marc Gravellはどうしますか?

この場合、彼はFastMemberを使用します。そして、あなたもそうするべきです。 Dapperのデータ変換の基礎となり、独自のDataReaderをオブジェクトにマップするのに簡単に使用できます(Dapperを使用しない場合)。

ご注意:

以下は私が私のSQLCMD抽象化レイヤで毎日使用し、拡張メソッドでこのコードは、FastMemberに依存することを意味し、簡単に変換することができても(.NETのコアのために書かれています。 NET Framework /標準に準拠したコード)。

public static T ConvertToObject<T>(this SqlDataReader rd) where T : class, new() 
{ 
    Type type = typeof(T); 
    var accessor = TypeAccessor.Create(type); 
    var members = accessor.GetMembers(); 
    var t = new T(); 

    for (int i = 0; i < rd.FieldCount; i++) 
    { 
     if (!rd.IsDBNull(i)) 
     { 
      string fieldName = rd.GetName(i); 

      if (members.Any(m => string.Equals(m.Name, fieldName, StringComparison.OrdinalIgnoreCase))) 
      { 
       accessor[t, fieldName] = rd.GetValue(i); 
      } 
     } 
    } 

    return t; 
} 
関連する問題