0

貧乏人のORMとレガシーアプリケーション(.NET 2.0 Webアプリ、手書きのSQLクエリ)を実装しています。私は2つのデータクラスを持っています:CustomerOrder

Public Class Customer
    Public Property CustomerId As Integer
    Public Property CustomerName As String
    Public Property Orders As List(Of Order)
End Class

Public Class Order
    Public Property OrderId As Integer
    Public Property OrderItem As String
End Class

を使用して、SQL結果をクラスSqlDataReaderのインスタンスに手動でマップしています。Customer

Dim connection As New SqlConnection(connectionString)
Dim command As New SqlCommand(sql, connection)
Dim reader As SqlDataReader()

connection.Open()

reader = command.ExecuteReader()

Dim customer As New Customer()

While reader.Read
    With customer
        .CustomerId =   reader("CustomerId")
        .CustomerName = reader("CustomerName")
        .Orders =       getOrdersByCustomerId(reader("CustomerId"))   ' get orders
    End With
End While

connection.Close()

を設定するために、 :Customer.Ordersを返す関数を呼び出します。List(Of Order)

Private Function getOrdersByCustomerId(ByVal customerId As Integer) As List(Of Order)

    Dim connection As New SqlConnection(connectionString)
    Dim command As New SqlCommand(sql, connection)
    Dim reader As SqlDataReader()

    connection.Open()

    reader = command.ExecuteReader()

    Dim orders As New List(Of Order)

    While reader.Read
        Dim order As New Order
        With order
            .OrderId =   reader("OrderId")
            .OrderItem = reader("OrderItem")
        End With
        orders.Add(order)
    End While

    connection.Close()

    Return orders

End Function

このメソッドのパフォーマンス、つまり複数のをプルする場合のパフォーマンスが心配ですCustomer。プルするたびCustomerに、データベースに再度アクセスして(別の接続を開き)、その特定の顧客の注文を取得する必要があります。私が誤解していなければ、開いている接続を大量に蓄積するのに多くのレコードは必要ありません。

私の質問は2つあります。

  1. 作成されている新しい接続の数と、接続プールまたはその他の.NETによって課せられた制限に遭遇するかどうかをどのように判断できますか?
  2. もっと良い方法はありますか?(以下のコメントを参照)

私が持っていた1つの考えはSQLConnection、呼び出し元のクラスで作成されたオブジェクトをgetOrdersByCustomerId関数に渡し、その関数に(明らかに?)すでに開いている接続を使用させることです。つまり、既存の方法よりも優れているかどうかを判断する方法がわからないため、テストしていません。考え?


バックグラウンド:

クライアントによる処理のためにJSONを返す検索Webサービスを作成しています。このサービスは、単一の検索パラメーターを受け取り、異なるテーブルで複数のルックアップを実行してから、カスタムJSONオブジェクトを返します。たとえば、ユーザーが名前のように見えるものを入力した場合、テーブルで上位n人の顧客Customersのリストを検索し、テーブルでその名前の顧客がいる上位n件の注文を検索します。Orders

4

4 に答える 4

3

接続を開いたり、再度開いたりするのは事実上無料です。したがって、接続を開いてできるだけ早く、できればusingブロックに破棄することをお勧めします。

接続文字列に追加することで、接続リークをテストできMax Pool Size=1;ます。これにより、使用可能な接続の数が1に制限されます。接続をリークすると、エラーが発生します。この設定を本番環境で使用しないように注意してください。

パフォーマンスのために、通常、大きなセットのすべての行でデータベースにアクセスすることは避けます。したがって、関連するすべての顧客のすべての注文を返す新しいクエリまたはプロシージャを作成できます。ただし、実際には、これは珍しいクエリです。通常は顧客のリストを表示し、エンドユーザーがその顧客にズームインしたときにのみ注文のリストを取得します。

于 2012-05-30T22:30:29.333 に答える
3

まず、が欠落しているためUsing Statement、コードをGarbage Collector自動的に破棄するのではなく、次のようにする必要があります。

Using connection As New SqlConnection("connectionString")
    Using command As New SqlCommand("sql", connection)
        Using reader As SqlDataReader = Nothing

            connection.Open()

            reader = command.ExecuteReader()

            Dim customer As New Customer()

            While reader.Read
                If True Then
                    customer.CustomerId = reader("CustomerId")
                    customer.CustomerName = reader("CustomerName")
                    customer.Orders = getOrdersByCustomerId(reader("CustomerId"))
                End If
            End While
            connection.Close()
        End Using
    End Using
End Using

パフォーマンスに関する元のクエリに戻る

DataTableレコードが多い場合に使用します。DataTableオブジェクトは、上記と同様の方法でステートメントを使用して使用後に破棄されることに注意してください。したがって、レコードを追加するために反復を実行する必要はありません。

再びデータベースに移動します

ViewStateまたはSessionここでの使用を検討できますか。データに変更があった場合は、を使用することもできますSQLDependency

getOrdersByCustomerId(reader( "CustomerId"))

フォームの読み込み時に取得しているすべての顧客関連情報を持ってきて、それを保存することは可能ViewStateですか?データリーダーでは、データベースに何度もアクセスすることはお勧めしません。したがって、最後ViewStateにDataReaderIterationの変数にアクセスします。

于 2012-05-30T22:35:28.650 に答える
2

この質問のデータベース側で作業しています。
レコードの取得に使用されるsqlコマンドは何も表示されません

たとえば、IDで顧客をロードする場合は、注文もロードしてみてください。

SELECT CUSTOMERS.*, ORDERS.* 
FROM CUSTOMERS LEFT JOIN ORDERS 
     ON CUSTOMERS.ID = ORDERS.CUSTOMERID
WHERE CUSTOMERS.ID = @custID

このデータをメモリに保存すると、データベースに2回アクセスすることなく、顧客とその注文が作成されます。

于 2012-05-30T22:46:34.307 に答える
2

プーリングをオフにしない限り、接続について心配する必要はありません。そうしていれば、この質問をすることはありません。

ブロックを使用することをお勧めしますが、物事を少し明確にしたい場合。

Using connection = new SqlConnection(ConnectionString)
' Insert code here 
End Using

接続は最後に使用して破棄されます。デフォルトの動作であるため、接続はプールに戻り、次にコード(実際にはプールはappdomainによって実行されます)が必要になったときに再利用されます。デフォルトの期間(覚えているように2分)は何も必要ない場合は、その時点で完全に破棄されます。

PSメソッドに対してローカルなIDisposableを実装するものには、ブロックを使用することをお勧めします。

注文ごとにサーバーをヒットするので、決定的な答えはありません。注文のページを取得し、そこから注文オブジェクトのコレクションを作成すると、必要になる可能性が低いものを大量に取得しない限り、パフォーマンスが向上します。つまり、表示に必要なデータのみを取得します。負荷が多い場合は、ある種の遅延読み込みスキームを使用して必要なときにデータを取得するか、OrderSummary、OrderDetailなどの異なるクラスを使用します。

于 2012-05-30T22:47:16.473 に答える