环境
go 1.21.1 + sqlx 1.6.0
场景
使用 sql hooks 注册了新的驱动
执行查询的时候,就报错如下
跟踪后发现是在:github.com/go-sql-driver/mysql@v1.6.0/connection.go:365
参考与说明
Why would I not want to set interpolateParams=true?
gorm mysql 报错 driver skip fast-path; continue as if unimplemented
go mysql driver InterpolateParams
go-sql-driver interpolateparams参数优化
go-sql-driver/mysql的interpolateparams参数说明
解决
方法1. 使用预编译进行数据库操作
方法2. 在DSN中加入参数interpolateparams=true
研究
interpolateParams 的开关对性能有很大影响,该参数涉及到预编译等内容。
根据github readme里面的介绍当使用interpolateParams参数(即interpolateParams = true,默认为true)时,调用db.query()和db.call()方法时,query中的占位符(?)会被args所替换,生成一条sql语句,client只需发送这条语句给server执行即可。
如果关闭这一参数,db.call()和db.query()的执行会分成3步:
第一步是client发送query给server来预编译,
第二步client发送args给server用于执行预编译的语句,
第三步关闭预编译语句。
readme里面说得很清楚使用这个参数会减少传输的RTT
但此参数的开启对于DB.Prepare等预编译相关的方法是无影响的
性能差异
interpolateparams=false
interpolateparams=true
做了啥?此参数
请先明确了啥叫预编译
一般带参数的SQL执行流程
prepared -> execute -> close
- 客户端将该语句和参数发给mysql服务器
- mysql服务器编译成一个prepared语句,这个语句可以根据不同的参数多次调用
interpolateparams=true执行流程
execute -> close
- 在驱动中通过转义特殊字符,来实现防止SQL注入问题
- 减少了prepared网络请求
源码
在Exec
方法中调用
在Query
方法中调用
具体实现代码 - 转义特殊字符
转换成功后,发送一条SQL读取数据