mysql: Resource leakage: Error 1461: Can't create more than max_prepared_stmt_count statements (current value: 16382)
Issue description
For some reason, this suddenly started happening. It seems like this is happening because queries built as strings are being “Prepared” behind the scenes, which is not something you want when every query is unique. The queries are executed with tx.Exec(str) and therefore there is no obvious indication to the user that statements are being prepared, causing this error to be extremely confusing.
Please note, that I’m still not entirely sure what the issue is, but this ticket represents my best guess.
Example code
// Lazy error handling, because example
func (sqlConf DBConfig) ExampleOverPrepare(items map[uint64]SomeStruct) (affected []uint64) {
db, err := sql.Open("mysql", sqlConf.String()+"?parseTime=true")
if err != nil { return }
defer db.Close()
tx, err := db.Begin()
if err != nil { return }
for uid, item := range items {
queryStr := buildQuery(item) /* func(item SomeStruct) string */
res, err := tx.Exec(queryStr)
/* rest of block stubbed out */
}
if err := tx.Commit(); err != nil {
log.Println("[ERROR]", err)
return
}
return affected /* would have been set in stubbed out block */
}
Error log
Error 1461: Can't create more than max_prepared_stmt_count statements (current value: 16382)
(this is the only error message relating to DB at all, and they appear every time DB is accessed)
Configuration
Driver version (or git SHA):
0b58b37b664c21f3010e836f1b931e1d0b0b0685
Go version: run go version in your console
go version go1.9.2 linux/amd64
Server version: E.g. MySQL 5.6, MariaDB 10.0.20 MySQL 5.6.32-78.0-log
Server OS: E.g. Debian 8.1 (Jessie), Windows 10 Unknown
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 1
- Comments: 17 (7 by maintainers)
You can use interpolateParams to prevent queries being prepared
This is consistently reproducing the problem. Processes continue to increase until execution completes, then they all disappear. After the process runs but before the program terminates, you can run
mysql -uroot -e 'SHOW PROCESSLIST' | grep 'MYSQL_USER_FROM_GO_CLIENT' | wc -lto see all the processes still alive by the go client.What’s interesting is the number of processes. If the look is set to 100, processes at the end are 100. 1000 is 1000. but 10,000 is 1017. There is some sort of cap that’s not getting me to hit the
max_prepared_stmt_count- however this is still the same problem because the processes are left open. It’s possible that this problem is exacerbated by using gin on top of the problem itself.To configure max_prepared_stmt_count properly, you should know this:
DB.Exec(query, arg...), it may consume MaxConnections statements on server side.Tx.Prepare()in transaction, it may consume N * MaxConnections statements.So max_prepared_stmt_count should be larger than sum of all above. And you can reduce statement count easily by reducing connection. When you use some ORM or other toolkit which automatically manages prepared statement, you should know how many statements are used in it.
I close this issue for now. If you sure about there is leak, please reopen with reproducible complete example code.
@macdabby You need
DB.SetConnMaxLifetime(time.Second * 10). Default setting will keep connections eternally and it is very bad for MySQL.