【Go】Go Gorm Sqlite3 CreateInBatches 报错:too many SQL variable 排查与解决

2023-05-16

Go:1.17.7

Gorm:gorm.io/gorm v1.22.3

Gorm-Sqlite3-driver: gorm.io/driver/sqlite v1.2.4

mattn-Sqlite3: github.com/mattn/go-sqlite3 v2.0.1+incompatible

Sqlite3:3.40.0


如果是老手,看到这里 ,应该就可以知道问题在哪了,不过这个解决方法也因为我是菜鸟,后面一步一步才发现的。


场景

使用gorm CreateInBatches 功能,批量插入100个对象 A ,对象 A 有 17 个字段

// BatchCreate is 批量新增
func (a *A) BatchCreate(tx db.Client, batch []*A) error {
   return tx.Table(a.TableName()).CreateInBatches(batch, len(batch)).Error
}

执行过后,报错:too many SQL variable

如果想直接知道解决方案的,可以往后跳,下面的一些细节是我的排查思路


排查

之前碰到 too many SQL variable 的错误,是因为 gorm.where(“a=? and b=?”, a,b,c) 。类似这样子,原本需要 2 个参数就可以,但是传了 3 个的情况,会报 too many SQL variable

顺着这个思路,就开始排查是不是 CreateInBatches 的参数有问题,导致了 SQL 执行出错。

不过,很遗憾,拿着打印的 SQL 去执行,发现没有报错,能直接批量写入 100 条数据,holy shit。那只能去问度娘了。

搜:

  • gorm 批量写入 too many SQL variable
  • gorm CreateInBatches 的坑
  • gorm 批量写入上限

找了很多,发现都没找到点上,或者根本不想关,那只能回归源码。

too many SQL variable 会是谁的报错?

  • gorm
  • sqlite-driver
  • mattn-sqlite
  • sdk/database

我们知道 go 访问数据库,都是通过驱动去访问,最后执行的结果也还是数据库返回的,gorm 这一层只是封装了一下调用方式,让我们更好用。所以,焦点就回归到,是不是 sqlite3 数据库本身对批量写入的 sql 语句有限制?顺藤摸瓜,找到了答案。

https://sqlite.org/limits.html#max_variable_number

A host parameter is a place-holder in an SQL statement that is filled in using one of the sqlite3_bind_XXXX() interfaces. Many SQL programmers are familiar with using a question mark (“?”) as a host parameter. SQLite also supports named host parameters prefaced by “:”, “$”, or “@” and numbered host parameters of the form “?123”.

Each host parameter in an SQLite statement is assigned a number. The numbers normally begin with 1 and increase by one with each new parameter. However, when the “?123” form is used, the host parameter number is the number that follows the question mark.

SQLite allocates space to hold all host parameters between 1 and the largest host parameter number used. Hence, an SQL statement that contains a host parameter like ?1000000000 would require gigabytes of storage. This could easily overwhelm the resources of the host machine. To prevent excessive memory allocations, the maximum value of a host parameter number is SQLITE_MAX_VARIABLE_NUMBER, which defaults to 999 for SQLite versions prior to 3.32.0 (2020-05-22) or 32766 for SQLite versions after 3.32.0.

The maximum host parameter number can be lowered at run-time using the sqlite3_limit(db,SQLITE_LIMIT_VARIABLE_NUMBER,size) interface.

这个讲的是 sqlite3 parameter 最大限制数量,也就是在 SQL 语句中的占位符 ? (还有别的)。文中说,因为怕 SQL 语句里的 parameter 太多,例如到 1000000000 个,那会需要用到 G 为单位的存储,那会是灾难。为了防止分配如此巨大的内存空间,SQL 用 SQLITE_MAX_VARIABLE_NUMBER 这个配置来限制。重点来了:

  • 版本在 2020-05-22 号前的 3.32.0 默认 999
  • 版本在 3.32.0 后的默认 32766
验证一

注意,gorm 中的 CreateInBatches的第二个参数,是每次批量写入的数据长度,不是你要批量写入的数据的长度。例如你要批量写入 100 条,第二个参数写 50,那么就是分 2 次去 insert,是在一个事务里面。

查到这个信息后,当然要验证一下。验证的方式就是调整每次批量写入的数量,999 / 17 = 58.7(999 个 parameter,对象 A insert 需要 17 个 value),所有就测试了一下 58 和 59 分别的执行情况。

  • 58 :success
  • 59 :too many SQL variable
解决方案一

调整每次 CreateInBatches 的 batchSize,改为 50,合适的范围。

// 最后调整成,最多 50
func (a *A) BatchCreate(tx db.Client, batch []*A) error {
   return tx.Table(a.TableName()).CreateInBatches(batch, 50).Error
}

接着排查

可能你看到这里会有点奇怪,为什么解决了还要接着排查。不知道,你注意到没有,上线写着的是 3.32.0 前后有区别,我的 Sqlite3 版本是 3.40.0,那正常来说应该可以批量写入的呀,这是为什么呢?

Sqlite3 版本没问题,那会不会是 gorm sqlite 相关的包,版本兼容问题呢?

去看了 github 上 gorm、sqlite3-driver、mattn-sqlite3 的首页,发现都有新的版本

因为我用的 gorm 和 sqlite3-driver 包比较旧,就改成了:

Gorm: gorm.io/gorm v1.24.2

Gorm-Sqlite3-driver: : gorm.io/driver/sqlite v1.4.3

mattn-Sqlite3: github.com/mattn/go-sqlite3 v1.14.15

因为这个时候,我是用一个新的 project 测试,不是在原有的项目上面。

验证二

切换完版本,根本不用改 batchSize,一条过,OMG

解决方案二

更新到最新版本的 gorm,自动会更新 sqlite3-driver 的包

此时我还没有注意到其中一个细节

验证三

如果是最新版本问题,那么是不是在 gorm 中间版本的时候,说明了某个版本只能兼容到 sqlite3 3.32.0。于是我就翻了 gorm 的 release 发现 v1.3.2 版本写着 update sqlite3 driver。以为我发现了新大陆,被我找到了。

于是我把 gorm 版本改成了 v1.3.2,发现确实可以。正当我以为解决完问题的时候,我在我新的项目下改成 v1.2.4,也就是开头的版本,验证一下,就是因为版本太旧,不能兼容 Sqlite3 3.32.0 之后的版本的时候。我去,它竟然也可以

这是为什么?这是为什么?比对了一下 go mod,看下两边的包版本是不是哪里不一样。最终发现罪魁祸首:

mattn-Sqlite3: github.com/mattn/go-sqlite3 v2.0.1+incompatible

mattn-Sqlite3: github.com/mattn/go-sqlite3 v1.14.15

就是因为这两个包的不同。

验证四

旧项目不能更新到最新版本的 gorm,所以就用 replace 把包替换一下,很真的可以

解决方案三

多看看这些包的官方文档,在 https://github.com/mattn/go-sqlite3 写着:

NOTE: The increase to v2 was an accident. There were no major changes or features.

明确地写着 v2 不能用呀~~

这也是为什么我在前面说的,老手,一眼就可以看出来

引申问题

go mod,为什么会去拉取到 v2 的包,我还没有分析出来


总结

虽然兜兜转转,最后竟然是因为包的缘故,导致了 too many SQL variable,不过还是学到了很多东西。也让我注意了批量写入时,是需要注意批量写入的大小的。也不是看到默认值是 32766,那就意味着我可以一次性干到最大,这个想法是不对的。在 https://github.com/mattn/go-sqlite3/issues/704 这个 issue 有提到类似的问题,最下面有一个写法,是用 Prepare ,然后每次都批量写入一些,然后完成你最后需要批量写入的数据。再看了下 gorm 的 CreateInBatches,是一样的效果。


解决方案

  • 限制批量写入的数量,太大性能可能就会下降
  • 删掉旧的 go mod,拉取最新的包,在够用的前提下,不见得最新就是最好的
  • 多学习,多看源码

启发文章

https://blog.csdn.net/lovelyelfpop/article/details/51064664

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Go】Go Gorm Sqlite3 CreateInBatches 报错:too many SQL variable 排查与解决 的相关文章

  • Unity3d 5.3.5使用sqlite3

    国内讲的乱七八糟 xff0c 更有故作神秘提供Mono Data Sqlite dll System Data dll的 xff0c 就是不告诉你这两文件在哪里 我很无语 看国外的 xff0c 多靠谱 http answers unity3
  • git Filename too long

    全局 git config global core longpaths true 当前仓库 git config core longpaths true 转载于 https www cnblogs com EasonJim p 108038
  • Ubuntu 20.04: harfbuzz version too old解决方法

    参考链接 xff1a unix stackexchange com 现象 在ubuntu20 04上安装了Ao xff08 可以看做Microsoft todo的linux版 xff09 xff0c 从终端启动时报错 xff1a Faile
  • mysql trigger 使用以及与 sqlite3 trigger 比较

    一 触发事件的表与触发更新的表使用同一个表 使用情景 xff0c 表里的某行数据发生update时自动更新修改时间 updated sqlite3 3 40 0 MariaDB 10 10 2 对应 MySQL 8 1 sqlite3 up
  • php 上传文件 出现413 Request Entity Too Large问题的解决方法

    配置 xff1a php 43 nginx 需求 xff1a 上传小文件正常 xff0c 上传大于2M 的PDF文件就提示 出现413 Request Entity Too Large问题的解决方法 经过排查 xff0c 这是nginx 拦
  • j记录一次gorm 使用协程 插入数据一直报错问题 -Duplicate entry ‘95‘ for key ‘PRIMARY‘ [14.649ms] [rows

    文章目录 问题描述问题解决 问题描述 报错代码如下 span class token keyword func span span class token function GetSystemInfoSave span span class
  • 《Towards Efficient SpMV on Sunway Many-core Architectures 》读后笔记

    记待解问题为y 61 Ax xff0c 采用了CSR格式存储矩阵 核心思路 xff1a 多级数据并行 具体分为两方面 xff0c 待计算数据的划分和计算核的划分 下面分3部分进行说明 1 xff09 对稀疏矩阵进行三级数据划分 xff0c
  • ssh 连接错误 Too many authentication failures 解决方法

    ssh 连接错误 Too many authentication failures 解决方法 背景 有时候使用 ssh 登录 或者 git ssh 方式连接 时会遇到 xff1a Too many authentication failur
  • 解决gorm中文表名或表头报错和乱码问题,gorm中文报错如何解决?

    文章目录 报错解决方案原因分析 报错 2021 11 20 16 39 51 C Users asus 3D Objects 个人项目 go网络编程测试 GormTest 主 go 45 Error 1300 Invalid utf8 ch
  • Django实战(自定义模块+Echart Tree+sqlite3)

    主要从以下这些方面依次介绍这次django实战经验 xff1a 数据处理django基本框架搭建sqlite3数据库Json数据Echart树状图Jquery 异步刷新laydate 日期查询前后端交互 数据处理 从本地文件夹中获得所有源文
  • pytoch报错OSError: [Errno 24] Too many open files

    因为默认的file descriptor共享策略使用文件描述符作为共享内存句柄 xff0c 并且当DataLoader上有太多批次时 xff0c 这将达到限制 要解决此问题 xff0c 您可以通过将其添加到脚本来切换到file system
  • python sqlite3

    含数据库连接 表创建 增删改查 查看sqlite数据库的软件推荐使用sqlitestudio 下载地址 sqlitestudio SQLite文档类资源 CSDN下载 coding utf 8 乐乐感知学堂公众号 author https
  • 详细使用sqlite3教程及打包资源

    包含编译好的unicode 多字节两种静态库 和sqlite3 h 还有我自己写的详细使用sqlite3的类 完整可用 实际项目我用过 有不对的地方还请大家批评指正 https download csdn net download qq 3
  • sqlite3编译和使用

    前言 SQLite 是一个 C 语言库 它实现了一个 小型 快速 自包含 高可靠性 功能齐全的SQL 数据库引擎 SQLite 是世界上使用最广泛的数据库引擎 SQLite 内置于所有手机和大多数计算机中 并捆绑在人们每天使用的无数其他应用
  • 使用python和pyqt5轻松上手人脸识别系统(含代码)

    使用python和pyqt5轻松上手人脸识别系统 含代码 一 环境配置 1 1 python环境配置 1 1 1 安装 anaconda 1 1 2 安装pycharm 1 1 3 配置pip源 1 2 mysql数据库安装 1 3 相关依
  • sqlite3的交叉编译

    比如说我们在qtcreator中编写程序的时候想用到sqlite3数据库 但是因为qtcreator中的编译器中的库中并没有sqlite3的库 所以肯定编译不了 所以若想在qtcreator中编译sqlite3的程序 首先的将sqlite3
  • gorm基础05--CRUD 接口-更新

    gorm基础05 CRUD 接口 更新 介绍 案例 说明 介绍 上文 gorm基础04 CRUD 接口 查询 介绍了gorm 中常见查询方法 本文继续介绍gorm中常见的更新方法 具体包括 保存所有字段 更新单个列 更新多个列 更新选定字段
  • 基于QT的人脸识别考勤管理系统【一】

    前言 上篇我们已经用opencv实现了人脸识别https blog csdn net qq 42449351 article details 99052241 现在我们就用人脸识别来做一个考勤管理系统 该系统开发工具是 win10 Qt C
  • 嵌入式数据库——sqlite3

    前言 数据库是 按照数据结构来组织 存储和管理数据的仓库 是一个长期存储在计算机内的 有组织的 可共享的 统一管理的大量数据的集合 数据库是以一定方式储存在一起 能与多个用户共享 具有尽可能小的冗余度 与应用程序彼此独立的数据集合 可视为电
  • c++调用sqlite3(带加解密)

    StringConvert见https blog csdn net wxd090108 article details 84190762 第三方文件 下载地址 https sourceforge net projects wxcode fi

随机推荐