gpt4 book ai didi

mysql - 限制最大准备语句数

转载 作者:IT王子 更新时间:2023-10-29 02:01:05 25 4
gpt4 key购买 nike

问题

我编写了一个将数据从 BigQuery 同步到 MySQL 数据库的应用程序。我尝试每 3 小时分批插入大约 10-20k 行(每批最多 10 项)。出于某种原因,当它尝试将这些行更新插入 MySQL 时,我收到以下错误:

不能创建超过 max_prepared_stmt_count 个语句:

Error 1461: Can't create more than max_prepared_stmt_count statements (current value: 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 batches
func 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, ","))

// placeholderstring for all to be inserted values
placeholderString := createPlaceholderString(tableFields)
valuePlaceholderString := ""
values := []interface{}{}
for _, row := range skuCosts {
valuePlaceholderString += fmt.Sprintf("(%s),", placeholderString)
values = append(values, row.ProjectName, row.SkuID, row.SkuDescription, row.UsageStartTime,
row.UsageEndTime, row.Cost, row.Currency, row.UsageAmount, row.UsageUnit,
row.UsageAmountInPricingUnits, row.UsagePricingUnit, row.InvoiceMonth)
}
valuePlaceholderString = strings.TrimSuffix(valuePlaceholderString, ",")

// put together SQL string
sqlString := fmt.Sprintf(`INSERT INTO
project_sku_cost %s VALUES %s ON DUPLICATE KEY UPDATE invoice_month=invoice_month`, tableFieldString, valuePlaceholderString)
sqlString = strings.TrimSpace(sqlString)

stmt, err := db.Prepare(sqlString)
if err != nil {
log.Warn("Error while preparing SQL statement to upsert project sku costs. ", err)
return 0
}

// execute query
res, err := stmt.Exec(values...)
if err != nil {
log.Warn("Error while executing statement to upsert project sku costs. ", err)
return 0
}

rowsAffected, err := res.RowsAffected()
if err != nil {
log.Warn("Error while trying to access affected rows ", err)
return 0
}

return rowsAffected
}

// createPlaceholderString creates a string which will be used for prepare statement (output looks like "(?,?,?)")
func createPlaceholderString(tableFields []string) string {
placeHolderString := ""
for range tableFields {
placeHolderString += "?,"
}
placeHolderString = strings.TrimSuffix(placeHolderString, ",")

return placeHolderString
}

我的问题:

当我立即执行准备好的语句(参见函数 upsertProjectSkuCosts)时,为什么我会命中 max_prepared_stmt_count

我只能想象它是某种并发,它在准备和执行所有这些语句之间同时创建大量准备好的语句。另一方面,我不明白为什么会有这么多并发,因为 ProcessProjectSkuCost 中的 channel 是一个大小为 20 的缓冲 channel 。

最佳答案

您需要关闭 upsertProjectSkuCosts() 中的语句(或重新使用它 - 请参阅本文末尾)。

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

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

您还可以做的是,准备一次语句并使其可用于 upsertProjectSkuCosts(通过将 stmt 传递到 upsertProjectSkuCosts 或通过使 upsertProjectSkuCosts 成为一个结构的函数,这样结构就可以拥有 stmt 的属性)。如果这样做,您应该调用stmt.Close() - 因为您不再创建新的语句,而是重新使用现有的语句。

另见 Should we also close DB's .Prepare() in Golang?https://groups.google.com/forum/#!topic/golang-nuts/ISh22XXze-s

关于mysql - 限制最大准备语句数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54004494/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com