我有一个相对简单的例程,查看媒体文件的数据库条目,计算宽度,高度和文件大小,并将它们写回数据库。
数据库是SQLite,使用System.Data.SQLite库,处理~4000行。我将所有行加载到ADO表中,使用新值更新行/列,然后运行adapter.Update(table);在它上面。
从db表中加载数据集大约半秒左右,更新所有具有图像宽度/高度的行并从FileInfo获取文件长度大约需要30秒。细
adapter.Update(table);命令在5到7分钟左右的某个地方运行。
这看起来非常过分。 ID是一个PK INTEGER,因此 - 根据SQLite的文档,它本身就是索引的,但即使如此,我也无法帮助,但我认为如果我为每个单独的更新运行单独的更新命令,会完成得更快。
我认为ADO /适配器的级别相对较低(而不是ORM),这种可怕的性能让我感到惊讶。任何人都可以了解为什么需要5-7分钟来更新一批~4000条记录来对照本地放置的SQLite数据库?
作为一个可能的旁边,是否有一些方法可以窥探" 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;
}
答案 0 :(得分:2)
从db表中加载数据集半秒左右
这是一个单独的SQL语句(所以它很快)。执行SQL SELECT,填充数据集,完成。
使用图像宽度/高度更新所有行并获取文件 FileInfo的长度大约需要30秒。细
这是更新内存数据(这样也快),更改数据集中的x行,根本不与SQL对话。
adapter.Update(table);
命令占据了5附近的某个地方 跑了7分钟。
这将为每个更新的行运行SQL更新。这就是为什么它很慢。
即便如此,我还是忍不住想,如果我要独立一人 每个更新的更新命令,这将完成 更快。
这基本上就是它正在做的事情!
来自MSDN
更新以逐行执行。每插入一次, 修改和删除行,Update方法确定类型 已对其执行的更改(插入,更新或删除)。 根据更改类型,“插入”,“更新”或“删除”命令 模板执行以将修改的行传播到数据源。 当应用程序调用Update方法时,DataAdapter会检查 RowState属性,并执行所需的INSERT,UPDATE或 根据的顺序,对每行迭代语句 在DataSet中配置的索引。
有没有办法“窥视”ADO如何处理这个?
答案 1 :(得分:0)
使用 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()
这大大加快了更新速度。