2012-04-25 21 views
1

Webサービスコールを介してアプリケーションからすべての「リクエスト履歴」ログを収集する、必要に応じて実行されるpowershellプロセスがあります。結果リクエストはオブジェクトにキャストされ、NoteProperty値(属性値ペア)は週ごとに大きなリスト配列(通常は1400項目)になります。データテーブルの適切な使用

私がやりたかったのは、これらの要求のすべてを歴史的な目的で保存して、アプリケーションがそれ自体でパージしないようにすることでした。したがって、私は、新しく作成したデータベースには存在しない各リクエストのすべての属性値のペアを格納するデータベース上に単純なテーブルを作成しました。

次に、powershellスクリプトでMSSQLサーバーにOleDB接続を設定し、テーブルからすべてのレコードを選択してDataTable(OleDBまたはDataTablesにはうまくいかない)を入力します。その後、リスト配列内の各項目をループして、DataTableには存在しないことを検証します。存在しないレコードごとに、属性と値のペアを持つDataTableに新しい行を追加します。そこから、私はコマンドビルダがInsert文を手助けすると仮定しているので、ヌルまたは空白の場合、またはクエリをまったく記述しなくても、各属性値をチェックする必要はありません。次に、OleDBAdapterを新しく追加されたDataTableで「更新」します。

このプロセスがうまくいく間、データベースからすべてのデータをプルダウンしてから、リスト配列と比較して新しく追加されたレコードを再コミットすることがわかりました。データベースが大きくなればなるほど、これにかかる時間は長くなります。 SQL文を書くことなく、すばやく効率的にこれを実行する方法はありますか? CommandBuilderがDataTableでどのように動作するのが好きです。すべての「リクエスト履歴」オブジェクトが

function UpdateDatabase([Parameter(Mandatory=$true)] $allRequests) 
{ 
    $objOleDbConnection = New-Object "System.Data.OleDb.OleDbConnection" 
    $objOleDbCommand = New-Object "System.Data.OleDb.OleDbCommand" 
    $objOleDbAdapter = New-Object "System.Data.OleDb.OleDbDataAdapter" 
    $objDataTable = New-Object "System.Data.DataTable" 

    $objOleDbConnection.ConnectionString = "Provider=SQLNCLI10;Server=SERVER;Database=DB1;Trusted_Connection=yes;" 
    $objOleDbConnection.Open() 

    $objOleDbCommand.Connection = $objOleDbConnection 
    $objOleDbCommand.CommandText = "SELECT * FROM dbo.RequestLog" 

    ##set the Adapter object and command builder 
    $objOleDbAdapter.SelectCommand = $objOleDbCommand 
    $objOleDbCommandBuilder = New-Object "System.Data.OleDb.OleDbCommandBuilder" 
    $objOleDbCommandBuilder.DataAdapter = $objOleDbAdapter 

    ##fill the objDataTable object with the results 
    [void] $objOleDbAdapter.Fill($objDataTable) 
    [void] $objOleDbAdapter.FillSchema($objDataTable,[System.Data.SchemaType]::Source) 

    #store all the primary keys in a list for kicking out dups 
    $sql_id = @() 
    $objDataTable.Rows | foreach { $sql_id += $_.PKID} 

    ##### 

    #loop through all the requests 
    trap { 
    "Error: $($i)" 
    } 
    $i = 0 
    $total = $allRequests.count 
    foreach ($request in $allRequests) 
    {  
     $i++ 
     write-progress -activity "Filling DataTable" -status "% Complete: $($i/$total*100)" -PercentComplete ($i/$total*100) 
     #check to see if entry already exists in our table (by primary key) 
     if (!($sql_id -contains $request.PKID.Value)) 
     { 
      #shouldn't have to do this but i noticed sometimes requests are duplicate in the list? (probably restarted the script and caught some old requests 
      $sql_id += $request.PKID.Value 

      $row = $objDataTable.Rows.Add($request.PKID.Value) 
      #go through all the attributes from the request and add them to the table 
      $list = get-member -in $request | Where-Object { $_.MemberType -eq "NoteProperty" } 
      foreach ($attr in $list) 
      { 
       if ($request.($attr.name) -ne $null) 
       { 
        $row.($attr.name) = $request.($attr.name) 
       } 
      } 

     } else { 
      #PKID already in DB 
     } 

    } 
    #update the database with our new records 
    $objOleDbAdapter.Update($objDataTable) 

    ## close the connection 
    $objOleDbConnection.Close() 
} 

答えて

1

あなたがプロセスをより作るために少しT-SQLコードを記述する必要があるとしているがフェッチされた後、以下

は、データベースを更新するために呼び出される関数です効率的。新しい行をSQL​​ Serverに送信して、処理がSQL Server上で行われるようにする必要があります。 1つの解決策は、DataTableをSQL Serverに渡すことを可能にするTable Valued Parametersを使用することです。私はわからないが、私は、ストアドプロシージャを作成するためのアクセス権を持っている場合

http://sev17.com/2012/04/appending-new-rows-only/

+0

おかげで@chad、私は、テーブル値パラメータを使用してになります:私はここに例をブログました –