2012-01-17 14 views
0

次のコードでは、F#を使用してSQLテーブルに行を挿入または更新したいと考えています。 ユーザーを表すタプルの行列と、いくつかのF#計算の結果である関連スコア(usrID、score)を取ります。
ここで、UserScoresTableというSQLテーブルを更新したいとします。
私が書いたコードは動作していますが、非常に遅いです。F#にストアドプロシージャを含める方法

let cnn = new System.Data.SqlClient.SqlConnection(ConfigurationManager.ConnectionStrings.Item("Database").ConnectionString) 
cnn.Open() 

// Definition d'une fonction qui execute une demande sous MySQL 
let execNonQuery s = 
    let comm = new System.Data.SqlClient.SqlCommand(s, cnn, CommandTimeout = 10) 
    comm.ExecuteNonQuery() |> ignore 

// Definition d'une fonction qui utilise les éléments d'une matrice pour updater une table dans MySQL 
let updateMySQLTable (m : Matrix<float * float>) = 
    for j in 0 .. (snd m.Dimensions) - 1 do 
     for i in 1 .. (fst m.Dimensions) - 1 do 
     // first check if the user and score and date do not exist 
      sprintf "IF NOT EXISTS (SELECT * FROM ProductScores WHERE UserID = %f AND ProductID = %f) INSERT INTO ProductScores (UserID, Score, Date) VALUES (%f, %f,CURRENT_TIMESTAMP)" (fst m.[i, j]) (snd m.[i, j]) 
      |> execNonQuery 
     // otherwise update the row 
      sprintf "UPDATE ProductScores SET Score = %f, Date = CURRENT_TIMESTAMP WHERE UserID = %f " (snd m.[i, j]) (fst m.[i, j]) 
      |> execNonQuery 

私は、このような

CREATE PROCEDURE updateScoreByUsers 
    -- Add the parameters for the stored procedure here 
    @UserID int, 
    @Score float 

AS 
BEGIN 

    IF NOT EXISTS 
    (SELECT * FROM ProductScores WHERE UserID = @UserID) 
     INSERT INTO 
     ProductScores (UserID, Score, Date) VALUES (@UserID,@Score,CURRENT_TIMESTAMP) 
    ELSE 

    UPDATE ProductScores 
     SET Score = @Score, Date = CURRENT_TIMESTAMP 
     WHERE UserID = @UserID 
END 
GO 

としてストアドプロシージャを使用してコード内の2つのexecNonQuery要求を避けたいしかし、私はF#でSQLストアドプロシージャを呼び出す方法を知りません。
F#でどのように呼び出すことができますか?
他に改善の方法がありますか?

+1

ADO.NETオブジェクトの管理は、少し壊れやすいようです。 – ChaosPandion

+1

MS SQLまたはMySQLを使用していますか? – ChaosPandion

+0

申し訳ありません私はMS SQLを使用しています。 – fabco63

答えて

3

SqlCommand.CommandTextをストアドプロシージャの名前に設定し、CommandTypeStoredProcedureに設定します。あなたは2008年にしている場合の例

use cmd = new SqlCommand("MyStoredProcedure", con) 
cmd.CommandType <- CommandType.StoredProcedure 
cmd.ExecuteNonQuery() 

のためには、MERGEステートメントに見てみたいことがあります。

パフォーマンスを大幅に向上させるには、各アイテムのデータベース呼び出しを避ける必要があります。おそらく、SqlBulkCopyを使用して、すべてのデータを一度にサーバーにロードし(一時表または指定されたステージング表を使用)、セット・ベース操作(UPDATE/INSERT/)を使用してターゲット表とマージします。

3

他の人に指摘されているように、単一のSQLコマンドで2つのステートメントを実行するだけでは、パフォーマンスが大幅に向上することはありません。効率を上げるには、データをMatrixからデータベースに転送してからテーブルを更新する必要があります。データをコピーするには、SqlBulkCopyMSDN for more infoを参照)を使用すると、大量のデータを効率的にアップロードできます。これを使用して、新しいテーブルにデータを挿入し、1つのSQLコマンドを実行して実際のテーブルのデータを更新することができます。


アサイド - ダニエルの答えは、F#のストアドプロシージャを呼び出す最も直接的な方法です。代わりに手でSqlCommandを作成し、実行するの

db?MyStoredProcedure(userId, scores) 

...:あなたはそれが少しよりよいようにしたい場合は、あなたも、あなたがこのような何かを書くのを聞かせてダイナミック演算子を使用することができます。これは、this MSDN articleに実装されているDynamicDatabaseタイプを使用して行うことができます。

+0

あなたのお勧めに基づいて、私はSQLBulkCopyを使用するつもりです、トーマスとダニエルありがとうございました。あなたがすでにこれを知っていると確信していますが、私の友人の一人が、すぐに来るはずの新しいF#アップデートには、SQLと通信するための便利な機能がいくつか含まれているということを教えてくれました。 http://msdn.microsoft.com/en-us/library/hh361033(v=vs.110).aspx – fabco63

関連する問題