2012-01-17 23 views
0

在下面的代碼中,我想通過F#插入或更新SQL表中的行。 它需要一個代表用戶的元組矩陣以及一些F#計算結果的相關分數(usrID,分數)。
現在我想更新一個名爲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 

,以避免在代碼中兩個execNonQuery請求,但我不知道該怎麼稱呼F#中的SQL存儲過程。
我如何用F#調用它?
您是否還有其他改進方法?

+1

您對ADO.NET對象的管理似乎有點脆弱。 – ChaosPandion 2012-01-17 18:27:26

+1

你使用的是MS SQL還是MySQL? – ChaosPandion 2012-01-17 18:28:18

+0

對不起,我正在使用MS SQL。 – fabco63 2012-01-17 18:31:16

回答

3

SqlCommand.CommandText設置爲存儲過程的名稱並將CommandType設置爲StoredProcedure。例如

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

如果你在2008年,你可能想看看進入MERGE聲明。

爲了顯著提高性能,你需要避免數據庫調用的每個項目。也許使用SqlBulkCopy將所有數據加載到服務器一次(使用臨時表或指定的臨時表),然後使用基於集的操作(UPDATE/INSERT/MERGE)與你的目標表合併。

3

正如指出的別人,只是做在一個SQL命令的兩個語句是不會改善多少性能。爲了使其真正高效,您需要將數據從Matrix傳輸到數據庫,然後更新表格。要複製數據,您可以使用SqlBulkCopy(請參閱MSDN for more info),它可以讓您高效地上傳大量數據。您可以使用它將數據插入到新表中,然後運行單個SQL命令來更新實際表中的數據。


另外 - 丹尼爾的答案是從F#調用存儲過程的最直接的方法。如果你想讓它更好一點,你也可以使用動態操作,這讓你寫的是這樣的:

db?MyStoredProcedure(userId, scores) 

...而不是創建和手工執行SqlCommand。這可以使用在this MSDN article中實現的DynamicDatabase類型來完成。

+0

謝謝托馬斯和丹尼爾,根據你的推薦,我將使用SQLBulkCopy。我相信你已經知道這一點,但爲了以防萬一,我的一位朋友告訴我,即將推出的新F#更新將包含一些與SQL通信的便捷功能。 http://msdn.microsoft.com/en-us/library/hh361033(v=vs.110).aspx – fabco63 2012-01-18 15:15:52

相關問題