为了账号安全,请及时绑定邮箱和手机立即绑定

限制最大准备语句数

限制最大准备语句数

Go
慕姐8265434 2023-05-22 17:44:25
问题我编写了一个将数据从 BigQuery 同步到 MySQL 数据库的应用程序。我尝试每 3 小时分批插入大约 10-20k 行(每批最多 10 项)。出于某种原因,当它尝试将这些行更新插入 MySQL 时,我收到以下错误:不能创建超过 max_prepared_stmt_count 个语句:错误 1461:不能创建超过 max_prepared_stmt_count 个语句(当前值:2000)我的“相关代码”// ProcessProjectSkuCost receives the given sku cost entries and sends them in batches to upsertProjectSkuCosts()func ProcessProjectSkuCost(done <-chan bigquery.SkuCost) {    var skuCosts []bigquery.SkuCost    var rowsAffected int64    for skuCostRow := range done {        skuCosts = append(skuCosts, skuCostRow)        if len(skuCosts) == 10 {            rowsAffected += upsertProjectSkuCosts(skuCosts)            skuCosts = []bigquery.SkuCost{}        }    }    if len(skuCosts) > 0 {        rowsAffected += upsertProjectSkuCosts(skuCosts)    }    log.Infof("Completed upserting project sku costs. Affected rows: '%d'", rowsAffected)}// upsertProjectSkuCosts inserts or updates ProjectSkuCosts into SQL in batchesfunc upsertProjectSkuCosts(skuCosts []bigquery.SkuCost) int64 {    // properties are table fields    tableFields := []string{"project_name", "sku_id", "sku_description", "usage_start_time", "usage_end_time",        "cost", "currency", "usage_amount", "usage_unit", "usage_amount_in_pricing_units", "usage_pricing_unit",        "invoice_month"}    tableFieldString := fmt.Sprintf("(%s)", strings.Join(tableFields, ","))我的问题:为什么我max_prepared_stmt_count在立即执行准备好的语句时点击了(请参阅函数upsertProjectSkuCosts)?我只能想象这是某种并发性,它在准备和执行所有这些语句之间同时创建大量准备好的语句。另一方面,我不明白为什么会有这么多并发,因为通道中的通道ProcessProjectSkuCost是一个大小为 20 的缓冲通道。
查看完整描述

1 回答

?
泛舟湖上清波郎朗

TA贡献1818条经验 获得超3个赞

您需要关闭里面的声明upsertProjectSkuCosts()(或重新使用它 - 请参阅本文末尾)。

当您调用 时db.Prepare(),会从内部连接池中获取一个连接(如果没有任何空闲连接,则会创建一个新连接)。stmt.Exec()然后在该连接上准备该语句(如果调用时该连接不可用,则该语句也会在另一个连接上准备)。因此,这会在您的数据库中为该连接创建一个语句。这个语句不会神奇地消失——在一个连接中有多个准备好的语句是完全有效的。Golang可以看到stmt超出范围,看到它需要某种清理然后进行清理,但 Golang 不会(就像它不会为您关闭文件和类似的东西一样)。所以你需要自己使用stmt.Close(). 你打电话时stmt.Close(),驱动程序将向数据库服务器发送命令,告诉它不再需要该语句。

defer stmt.Close()最简单的方法是在检查后添加err以下内容db.Prepare()

您还可以做的是,准备一次语句并使其可用于upsertProjectSkuCosts(通过将stmtinto传递upsertProjectSkuCosts或通过构造upsertProjectSkuCosts结构的 func,以便结构可以具有 的属性stmt)。如果你这样做,你应该调用stmt.Close()- 因为你不再创建新的语句,你正在重新使用现有的语句。

查看完整回答
反对 回复 2023-05-22
  • 1 回答
  • 0 关注
  • 120 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信