Go MySQL SELECT @@max_allowed_packet

SELECT @@max_allowed_packet

我们使用的是 阿里云的 RDS, 它提供了很棒的数据库优化服务,可以定期观察,清理一些慢查询。

慢SQL明细 里面, 发现最近一周有不少的 SQL :

1
SELECT @@max_allowed_packet

我们使用的是 Golang 去连接 MySQL, 通过全局搜索 max_allowed_packet, 发现在 github.com/go-sql-driver/mysql 中存在如下逻辑:

1
2
3
4
5
6
7
8
9
10
11
if mc.cfg.MaxAllowedPacket > 0 {
mc.maxAllowedPacket = mc.cfg.MaxAllowedPacket
} else {
// Get max allowed packet size
maxap, err := mc.getSystemVar("max_allowed_packet")
if err != nil {
mc.Close()
return nil, err
}
mc.maxAllowedPacket = stringToInt(maxap) - 1
}
1
2
3
4
5
6
7
8
9
10
// Gets the value of the given MySQL System Variable
// The returned byte slice is only valid until the next read
func (mc *mysqlConn) getSystemVar(name string) ([]byte, error) {
// Send command
if err := mc.writeCommandPacketStr(comQuery, "SELECT @@"+name); err != nil {
return nil, err
}

// ignored
}

根据上面代码发现如果没有配置 MaxAllowedPacket, 那么就会向 MySQL 发送 查询 max_allowed_packet 的命令, 所以只要配置了MaxAllowedPacket 就可以避免发送命令.

dsn.goparseDSNParams 方法中:

1
2
3
4
5
case "maxAllowedPacket":
cfg.MaxAllowedPacket, err = strconv.Atoi(value)
if err != nil {
return
}

发现只要在 MySQL 的 dsn 中配置 maxAllowedPacket 这个参数即可:

1
2
maxPacketSize := 1<<30 - 1 // 1G, to avoid send query: SELECT @@max_allowed_packet
dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?parseTime=true&loc=Local&charset=utf8mb4,utf8&timeout=3s&readTimeout=30s&writeTimeout=30s&maxAllowedPacket=%d", user, password, host, db, maxPacketSize)