SQLite 批量插入未通过事务加速

问题描述 投票:0回答:1

我正在尝试创建一个辅助函数,使 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 毫秒。对于一条记录来说,这是可以忽略不计的,但我试图一次插入数百条记录,这正在成为一个严重的瓶颈。

我尝试过的事情:

  • 在每次执行中批量执行多个插入。这根本不影响吞吐量
  • 重用参数。没有变化
  • 交易。我在网上看到的每个消息来源都指出交易可以解决这个问题,但添加交易却没有任何作用。我尝试直接复制微软的批量插入指南,但没有效果
sqlite f# microsoft.data.sqlite
1个回答
0
投票

问题不在于此处显示的任何代码,而在于其他几个表,它们都具有对

User
表的外键引用。有数十万条记录包含对
User
的外键引用,显然检查这么多的外键完整性实在是太多了。

数据完整性并不是这个项目的一个大问题,缺少关键引用也不是问题,所以我决定删除所有外键约束。我保留了主键约束,因为这对于我的用例来说非常重要。 在不使用外键的情况下重建数据库后,每批插入时间从之前的 10-30 秒以上减少到大约 10-30 毫秒。

对于未来遇到类似问题的任何人,在他们的项目中放弃外键约束是可以接受的,我找到了

本指南

存档)。

© www.soinside.com 2019 - 2024. All rights reserved.