我正在尝试创建一个辅助函数,使 SQLite 数据库的插入操作易于推广。
例如:
member __.RegisterUsers (users : UserData array) =
insertOrReplace "User" users [|
("id", fun u -> u.id)
("nick", fun u -> u.nick)
("is_verified", fun u -> u.is_verified)
("is_banned", fun u -> u.is_banned)
("subscriptions", fun u -> u.num.subscriptions)
("subscribers", fun u -> u.num.subscribers)
("total_posts", fun u -> u.total_posts)
("original_nick", fun u -> u.original_nick)
|]
我的实现如下:
let insertOrReplace (table:string) (items:'T array) (args:(string * ('T -> obj)) array)=
let fieldNames = args |> Seq.map fst |> Seq.toArray
let parameterNames = fieldNames |> Array.mapi (fun i name -> $"@{name}{i}")
let commandText =
StringBuilder()
.Append($"INSERT OR REPLACE INTO {table} (")
.AppendJoin(", ", fieldNames)
.Append(") VALUES (")
.AppendJoin(", ", parameterNames)
.Append(");")
.ToString()
use transaction = connection.BeginTransaction()
use command = new SqliteCommand(commandText, connection, transaction)
let parameters =
parameterNames |> Array.map (fun name ->
let parameter = command.CreateParameter()
parameter.ParameterName <- name
command.Parameters.Add(parameter)
)
try
let modifiedFields = items |> Array.map (fun item ->
Array.iter2 (fun (name, selector) (parameter:SqliteParameter) -> parameter.Value <- selector item) args parameters
command.ExecuteNonQuery()
)
transaction.Commit()
modifiedFields |> Array.sum |> Ok
with
| _ as ex -> Error ex.Message
这使用 Microsoft 的 Microsoft.Data.Sqlite 库
我尝试插入的表定义:
CREATE TABLE IF NOT EXISTS User (
id TEXT PRIMARY KEY,
nick TEXT NOT NULL,
is_verified INTEGER NOT NULL,
is_banned INTEGER NOT NULL,
subscriptions INTEGER NOT NULL,
subscribers INTEGER NOT NULL,
total_posts INTEGER NOT NULL,
original_nick TEXT NOT NULL
);
这“有效”是指数据插入正确,但速度非常慢,每条记录大约需要 75-110 毫秒。对于一条记录来说,这是可以忽略不计的,但我试图一次插入数百条记录,这正在成为一个严重的瓶颈。
我尝试过的事情:
问题不在于此处显示的任何代码,而在于其他几个表,它们都具有对
User
表的外键引用。有数十万条记录包含对 User
的外键引用,显然检查这么多的外键完整性实在是太多了。
数据完整性并不是这个项目的一个大问题,缺少关键引用也不是问题,所以我决定删除所有外键约束。我保留了主键约束,因为这对于我的用例来说非常重要。 在不使用外键的情况下重建数据库后,每批插入时间从之前的 10-30 秒以上减少到大约 10-30 毫秒。
对于未来遇到类似问题的任何人,在他们的项目中放弃外键约束是可以接受的,我找到了
本指南(存档)。