DataAdapter.Update() performance

本文关键字:performance Update DataAdapter | 更新日期: 2023-09-27 18:01:45

我有一个相对简单的例程,它查看媒体文件的数据库条目,计算宽度、高度和文件大小,并将它们写回数据库。

数据库为SQLite,使用System.Data.SQLite库,处理约4000行。我将所有行加载到ADO表中,用新值更新行/列,然后运行adapter.Update(table);。

从db表加载数据集大约需要半秒,用图像宽度/高度更新所有行并从FileInfo获取文件长度可能需要30秒。好。

adapter.Update(表);命令运行大约需要5到7分钟。

这似乎太过分了。ID是一个PK INTEGER,因此-根据SQLite的文档,是固有索引的,但即使如此,我还是忍不住想,如果我对每个单独的更新运行一个单独的更新命令,这将完成得更快。

我认为ADO/适配器是相对低级的(无论如何与orm相反),这种糟糕的性能使我感到惊讶。有没有人能解释一下,为什么在本地放置的SQLite数据库中更新一批4000条记录需要5-7分钟?

作为一个可能的旁白,是否有一些方法可以"窥视"到ADO是如何处理这个的?内部库步进还是…??

感谢
public static int FillMediaSizes() {
        // returns the count of records updated
        int recordsAffected = 0;
        DataTable table = new DataTable();
        SQLiteDataAdapter adapter = new SQLiteDataAdapter();
        using (SQLiteConnection conn = new SQLiteConnection(Globals.Config.dbAppNameConnectionString))
        using (SQLiteCommand cmdSelect = new SQLiteCommand())
        using (SQLiteCommand cmdUpdate = new SQLiteCommand()) {
            cmdSelect.Connection = conn;
            cmdSelect.CommandText =
                "SELECT ID, MediaPathCurrent, MediaWidth, MediaHeight, MediaFilesizeBytes " +
                "FROM Media " +
                "WHERE MediaType = 1 AND (MediaWidth IS NULL OR MediaHeight IS NULL OR MediaFilesizeBytes IS NULL);";
            cmdUpdate.Connection = conn;
            cmdUpdate.CommandText =
                "UPDATE Media SET MediaWidth = @w, MediaHeight = @h, MediaFilesizeBytes = @b WHERE ID = @id;";
            cmdUpdate.Parameters.Add("@w", DbType.Int32, 4, "MediaWidth");
            cmdUpdate.Parameters.Add("@h", DbType.Int32, 4, "MediaHeight");
            cmdUpdate.Parameters.Add("@b", DbType.Int32, 4, "MediaFilesizeBytes");
            SQLiteParameter param = cmdUpdate.Parameters.Add("@id", DbType.Int32);
            param.SourceColumn = "ID";
            param.SourceVersion = DataRowVersion.Original;
            adapter.SelectCommand = cmdSelect;
            adapter.UpdateCommand = cmdUpdate;
            try {
                conn.Open();
                adapter.Fill(table);
                conn.Close();
            }
            catch (Exception e) {
                Core.ExceptionHandler.HandleException(e, true);
                throw new DatabaseOperationException("", e);
            }
            foreach (DataRow row in table.Rows) {
                try {
                    using (System.Drawing.Image img = System.Drawing.Image.FromFile(row["MediaPathCurrent"].ToString())) {
                        System.IO.FileInfo fi;
                        fi = new System.IO.FileInfo(row["MediaPathCurrent"].ToString());
                        if (img != null) {
                            int width = img.Width;
                            int height = img.Height;
                            long length = fi.Length;
                            row["MediaWidth"] = width;
                            row["MediaHeight"] = height;
                            row["MediaFilesizeBytes"] = (int)length;
                        }
                    }
                }
                catch (Exception e) {
                    Core.ExceptionHandler.HandleException(e);
                    DevUtil.Print(e);
                    continue;
                }
            }                

            try {
                recordsAffected = adapter.Update(table);
            }
            catch (Exception e) {
                Core.ExceptionHandler.HandleException(e);
                throw new DatabaseOperationException("", e);
            }

        }
        return recordsAffected;
    }

DataAdapter.Update() performance

使用Connection.BeginTransaction()来加速DataAdapter的更新。

conn.Open() 'open connection
Dim myTrans As SQLiteTransaction
myTrans = conn.BeginTransaction() 
'Associate the transaction with the select command object of the DataAdapter
objDA.SelectCommand.Transaction = myTrans 
objDA.Update(objDT)
Try
    myTrans.Commit()
Catch ex As Exception
    myTrans.Rollback()
End Try
conn.Close()

这大大加快了更新。

从db表加载数据集大约半秒

这是一条SQL语句(所以速度很快)。执行SQL SELECT,填充数据集,完成。

用图像宽度/高度更新所有行并获取文件FileInfo的长度大概花了30秒。好。

这是更新内存中的数据(所以也很快),改变数据集中的x行,根本不需要SQL。

adapter.Update(table);命令的值在5附近到7分钟运行

这将为每个更新的行运行SQL更新。这就是为什么它很慢。

然而即便如此,我还是忍不住想,如果我要跑一个单独的对于每个单独的更新命令,这将完成更快。

这基本上就是它所做的!


从MSDN

行执行更新。对于每一次插入,修改和删除的行,Update方法确定的类型已对其执行的更改(插入、更新或删除)。根据更改的类型,可以使用Insert、Update或Delete命令模板执行以将修改的行传播到数据源。当应用程序调用Update方法时,DataAdapter进行检查并执行所需的INSERT、UPDATE或DELETE语句,根据的顺序,迭代地对每一行执行

数据集中配置的索引。

是否有办法"窥视"ADO是如何处理的?

是:调试。net框架的源代码在Visual Studio 2012?