mysql 踩坑记录,报错:Error 1390 (HY000): Prepared statement contains too many placeholders

db错误信息: Error 1390 (HY000): Prepared statement contains too many placeholders

可能的场景:批量插入数据、批量更新数据、查询数据的条件占位符过多时

根本原因:执行的SQL语句中包含了过多的占位符,MySQL对SQL语句中的占位符数量是有限制的(常见限制是65536个占位符)。

在 5.7版本的 MySQL 代码中看到:sql/sql_prepare.cc:(The maximum number of placeholders for values in a prepared statement is the maximum value of a 16-bit unsigned integer, or specfically: 65,536.)

static bool init_param_array(Prepared_statement *stmt)
{
  LEX *lex= stmt->lex;
  if ((stmt->param_count= lex->param_list.elements))
  {
    if (stmt->param_count > (uint) UINT_MAX16)
    {
      /* Error code to be defined in 5.0 */
      my_message(ER_PS_MANY_PARAM, ER(ER_PS_MANY_PARAM), MYF(0));
      return TRUE;
    }

批量插入更新时:写入数据为m列,n行时,必须保证 m*n < 65536

举例:比如下面这个SQL,插入字段 m=4,65536/4=16384,此时 len(data) 必须小于16384,否则就会报错Error 1390 ...

db.Select("material_id", "material_key", "status", "created_by").Create(data)

查询数据时:必须保证 查询条件的占位符 ?< 65536

举例:比如下面这个SQL,当 len(materialIds) = 65534,len(langs)=1 时能正常查询,当 len(materialIds) = 65534,len(langs)=2 时会报错Error 1390 ...

db.Model(MaterialLang{
   
   }).Where("material_id in ? and lang in ? and is_del = 0", materialIds, langs).Find(&list)

解决思路:分批处理

需要考虑:分批后整体耗时增加的问题

封装一个分批处理函数

1. 使用 goroutine 并发分批处理,缩短整体耗时(若需串行执行,配置并发数为1即可)

2. 使用 chan 控制并发数量,保护MySQL的过载使用

golang 代码

分批处理函数

func BatchProcess[T any](ctx context.Context, db *gorm.DB, list [
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值