亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

限制最大準備語句數

限制最大準備語句數

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 關注
  • 155 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號