Golang使用Sqlx库报错 skip fast-path; continue as if unimplemented

环境

go 1.21.1 + sqlx 1.6.0

场景

使用 sql hooks 注册了新的驱动
file
执行查询的时候,就报错如下
file
跟踪后发现是在:github.com/go-sql-driver/mysql@v1.6.0/connection.go:365
file

参考与说明

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
file
interpolateparams=true
file

做了啥?此参数

请先明确了啥叫预编译

一般带参数的SQL执行流程

prepared -> execute -> close

  1. 客户端将该语句和参数发给mysql服务器
  2. mysql服务器编译成一个prepared语句,这个语句可以根据不同的参数多次调用

interpolateparams=true执行流程

execute -> close

  1. 在驱动中通过转义特殊字符,来实现防止SQL注入问题
  2. 减少了prepared网络请求

源码

Exec方法中调用
file
Query方法中调用
file
具体实现代码 - 转义特殊字符
file
file
转换成功后,发送一条SQL读取数据
file