2013-07-01 107 views
3

我相信我用了很多方法來加速很多行的更新, 但是到目前爲止沒有什麼幫助。很多行的SQLite更新很慢

我們打開的是交易, 這樣的:

private SQLiteTransaction BeginTransaction(SQLiteConnection connection) 
{ 
    return connection.BeginTransaction(); 
} 

,並在課程結束時將其關閉。 我們打開一個連接,一個事務,然後我們更新數據庫上的很多行。 這意味着我們在許多表中累積了許多不同的SQL語句。

其中很大一部分是12000條記錄在一個表中

protected override void UpdateRows(SQLiteConnection connection, IEnumerable<DataRow> rowsToUpdate)  
{ 
    var command = new SQLiteCommand(Queries.SQLUpdateDocument, connection); 

     foreach (DataRow documentRow in rowsToUpdate) 
     { 
       command.Parameters.AddWithValue("@Filename", documentRow[Constants.Col_Document_Filename]); 
       command.Parameters.AddWithValue("@ClassID", documentRow[Constants.Col_Document_ClassID]); 
       command.Parameters.AddWithValue("@PageCount", documentRow[Constants.Col_Document_PageCount]); 
       command.Parameters.AddWithValue("@DocID", documentRow[Constants.Col_Document_GlobalDocID]); 
       command.Parameters.AddWithValue("@ReadOnly", documentRow[Constants.Col_Document_ReadOnly]); 
       command.Parameters.AddWithValue("@Confirmed", documentRow[Constants.Col_Document_Confirmed]); 
       command.Parameters.AddWithValue("@ParentFolderID", documentRow[Constants.Col_Document_ParentFolderID]); 
       command.Parameters.AddWithValue("@SequenceNumber", documentRow[Constants.Col_Document_SequenceNumber]); 
       command.Parameters.AddWithValue("@XmlRepr", documentRow[Constants.Col_Document_XmlRepr]); 

       command.ExecuteNonQuery(); 

       documentRow.AcceptChanges(); 
    } 
} 

與查詢beeing更新:

UPDATE T_Doc SET 
Filename = @Filename, 
ClassID = @ClassID, 
PageCount = @PageCount, 
ReadOnly = @ReadOnly, 
Confirmed = @Confirmed, 
ParentFolderID = @ParentFolderID, 
SequenceNumber = @SequenceNumber, 
XmlRepr = @XmlRepr 
WHERE ID = @DocID; 

中的AcceptChanges()並不需要很長時間。 ExecuteNonQuery()比預期的要慢得多。

PRAGMA foreign_keys = ON; 

更新命令和的ClassID和ParentFolderID參考其他表之前已被執行。

無論如何 - 更新速度非常慢,更新12000條記錄需要15-30分鐘。

有人可以幫我嗎?

+0

您的表格是否由ID字段索引?如果你能展示你如何組織表格,這可能有助於理解問題的根源。 – athabaska

+0

嘗試使用事務模型:open transaction-> execute ** all ** comands-> commit transaction。 – Tigran

+0

@athabaska ID是主鍵。 SQLite將自動創建主鍵。 – HankTheTank

回答

5

我懷疑你不打電話給BeginTransaction,或者你沒有將命令與事務相關聯......如果沒有明確指定事務,則每次執行命令時隱式創建一個新事務。

試試這個:

protected override void UpdateRows(SQLiteConnection connection, IEnumerable<DataRow> rowsToUpdate)  
{ 
    using (var command = new SQLiteCommand(Queries.SQLUpdateDocument, connection)) 
    using (var transaction = connection.BeginTransaction()) 
    { 
     command.Transaction = transaction; 

     foreach (DataRow documentRow in rowsToUpdate) 
     { 
       command.Parameters.AddWithValue("@Filename", documentRow[Constants.Col_Document_Filename]); 
       command.Parameters.AddWithValue("@ClassID", documentRow[Constants.Col_Document_ClassID]); 
       command.Parameters.AddWithValue("@PageCount", documentRow[Constants.Col_Document_PageCount]); 
       command.Parameters.AddWithValue("@DocID", documentRow[Constants.Col_Document_GlobalDocID]); 
       command.Parameters.AddWithValue("@ReadOnly", documentRow[Constants.Col_Document_ReadOnly]); 
       command.Parameters.AddWithValue("@Confirmed", documentRow[Constants.Col_Document_Confirmed]); 
       command.Parameters.AddWithValue("@ParentFolderID", documentRow[Constants.Col_Document_ParentFolderID]); 
       command.Parameters.AddWithValue("@SequenceNumber", documentRow[Constants.Col_Document_SequenceNumber]); 
       command.Parameters.AddWithValue("@XmlRepr", documentRow[Constants.Col_Document_XmlRepr]); 

       command.ExecuteNonQuery(); 

       documentRow.AcceptChanges(); 
     } 

     transaction.Commit(); 
    } 
} 

注意,如果你有一個非常大的行數,您可能需要提交您已經更新之前的一切,例如每1000行。在這種情況下,您需要在提交之前創建一個新的事務。

+1

我真的必須將交易分配給命令嗎?我相信它是自動設置的 – HankTheTank

+0

只是在整個'概念'交易完成之前提交交易的概念。雖然這是一種有效的潛在解決方法,但確實會失去單個事務提供的事務一致性。所以請謹慎使用,我建議僅將此作爲最後努力將插入性能提高到您想要的範圍內。這種方法確實會損失很多。 –

+0

@JakeHeidt,你是對的,但在這種情況下,交易的使用主要是提高性能的一種方式,而不是一種確保一致性的方法...... –