Prepared SQL 性能测试
一:Prepere Statement 简介
prepare statement 即 SQL 预处理。什么是 SQL 预处理? 普通 SQL 语句执行的逻辑 需要经过 server 层 的 分析器 (图中圈住的部分) 对 sql 语句进行词法语法解析、sql 编译,
这需要一些性能开销,尤其在一些高并发的场景中可能是性能提升的一个突破点。Prepere Statement 就是干这个事的,他可以对 SQL 进行预编译。 查看 MySQL 官方文档,
有这么一条说明:
Prepere Statement 适用的场景是,SQL 语句 未发生改变,只是 query 的值发生了改变的情况。通俗的讲就是,比如 有这么一条 SQL insert into t1(name, age) values ( "siri", 18 )
当你要批量执行时,Prepare 方法 可以用 占位符的方式填充 SQL 值变化的部分,即 insert into t1(name, age) values ( ?, ? ) ,可以由 Prepare 提交给 分析器预编译。下次再
执行的时候,直接 EXECUTE Statement 占位符填充,省去了再次 语法解析、编译的过程,达到一次编译,多次运行的效果。
那么,Prepere 在高并场景下,性能能提升多少呢,官方并未给出答案,下面准备实测一下:

二:Prepere Statement 性能测试
测试环境:(测试 批量 插入性能 )
- 测试实例:MySQl 5,7
- 配置: 4 核 8G
网上关于 prepare 性能测试的帖子很少, 于是需要自己写测试工具。( http://gitlab.xxxxx.com/master/mysql_prepare_test )
工具关键部分如下:
// Prepare SQL syntax
func PrepareExec(n int, wg *sync.WaitGroup) {
// NameExec
sqlStr := "insert into user(name,age) values(?,?)" // 占位符
stmt, _ := db.Prepare(sqlStr) // 开启 Prepare ,预编译 SQL 语句
defer stmt.Close()
defer wg.Done()
for i := 0; i <= n; i++ {
name := RandString(10)
_, err := stmt.Exec(name, 20)
if err != nil {
fmt.Println(err)
}
//rows, _ := ret.RowsAffected()
//record := fmt.Sprintf("RowsAffected: %d", rows)
//logger.Write(record)
}
}
// NonPrepare SQL syntax
func NonPrepareExec(n int, wg *sync.WaitGroup) {
// NameExec
defer wg.Done()
for i := 0; i <= n; i++ {
name := RandString(8)
sqlStr := "insert into user(name,age) values(?,?)"
_, err := db.Exec(sqlStr, name, 18) // 未 prepare 处理的普通 SQL
if err != nil {
fmt.Println(err)
}
//rows, _ := ret.RowsAffected()
//record := fmt.Sprintf("RowsAffected: %d", rows)
//logger.Write(record)
}
}
测试结果如下:
- 4 个线程,每个线程 100 个 insert:
未使用 prepare:
./prepare_test --prepare=false --t=4 --i=100
cost time:409.5343ms
使用 prepare:
./prepare_test --prepare=true --t=4 --i=100
cost time:275.1861ms
- 4 个线程,每个线程 300 个 insert:
未使用 prepare:
./prepare_test --prepare=false --t=4 --i=300
cost time:1.4089236s
使用 prepare:
./prepare_test --prepare=true --t=4 --i=300
cost time:791.6015ms
篇幅有限:测试汇总如下
- --t thread : 线程数
- --i insert : 每个线程 insert 语句总数
| 并发参数 | 未使用 Prepare | 使用 Prepare | 性能提升 |
|---|---|---|---|
| t=4 i=100 | 409.5343ms | 275.1861ms | 32% |
| t=4 i=300 | 1.4089236s | 791.6015ms | 42% |
| t=4 i=500 | 2.1703388s | 1.129176s | 47% |
| t=8 i=100 | 629.015ms | 297.4847ms | 52% |
| t=8 i=300 | 3.2628256s | 1.67031s | 50% |
| t=8 i=500 | 3.2897162s | 3.2978884s | 0% |
从测试结果看,使用 Prepare 进行 批量插入,和 普通的 sql 相比,性能提升在 30%-50% 之间,但是当超出 实例性能时用不用 Prepare 没有什么变化。
排除 其他干扰因素,保守估计 Prepare 批量插入时性能会提升在 20% - 40% 之间,这个变化还是比较明显的。
三:总结
- Prepere 的使用场景是,SQL 语句 未发生改变,只是 query 的值发生了改变的情况。尤其是高并发 批量 SQL 的场景。
- Prepere 在批量 插入时 性能提升在 20% - 40%。 但是 select / update 有待测试,感兴趣的同学可以测一下。
- 当 并发 达到 实例性能上限时,Prepare SQL 和 普通 SQL 的 性能没有明显变化。
- MySQL 5.6 版本开始支持 Prepere 预处理
参考文档:
https://dev.mysql.com/doc/refman/8.0/en/sql-prepared-statements.html
原创系列,转载请注明出处,谢谢!
Prepared SQL 性能测试的更多相关文章
- 发现美的眼睛 Prepared SQL Statement
DROP PROCEDURE IF EXISTS truncate_insert_sales_rank_toparow_month; DELIMITER /w/ CREATE PROCEDURE tr ...
- MySQL的SQL预处理(Prepared)
Prepared SQL Statement:SQL的执行.预编译处理语法.注意点 一.SQL 语句的执行处理1.即时 SQL 一条 SQL 在 DB 接收到最终执行完毕返回,大致的过程如下: 1. ...
- JDBC与Hibernate中SQL语句参数设置的顺序问题
JDBC中:设置从1开始 例: Connection con = DriverManager.getConnection("jdbc:mysql://localhost/...", ...
- SQL Server中关于跟踪(Trace)那点事
前言 一提到跟踪俩字,很多人想到警匪片中的场景,同样在我们的SQL Server数据库中“跟踪”也是无处不在的,如果我们利用好了跟踪技巧,就可以针对某些特定的场景做定向分析,找出充足的证据来破案. 简 ...
- 直接放个DB2 SQL STATEMENT大全好了!
SQL statements This topic contains tables that list the SQL statements classified by type. SQL sch ...
- 【转】SQL Server中关于跟踪(Trace)那点事
前言 一提到跟踪俩字,很多人想到警匪片中的场景,同样在我们的SQL Server数据库中“跟踪”也是无处不在的,如果我们利用好了跟踪技巧,就可以针对某些特定的场景做定向分析,找出充足的证据来破案. 简 ...
- SQL Server里强制参数化的痛苦
几天前,我写了篇SQL Server里简单参数化的痛苦.今天我想继续这个话题,谈下SQL Server里强制参数化(Forced Parameterization). 强制参数化(Forced Par ...
- 五、SQL映射的XML文件
MyBatis真正的力量是在映射语句中.这里是奇迹发生的地方.对于所有的力量,SQL映射的XML文件是相当的简单.当然如果你将它们和对等功能的JDBC代码来比较,你会发现映射文件节省了大约95%的代码 ...
- SQL Server 扩展事件(Extented Events)从入门到进阶(1)——从SQL Trace到Extented Events
由于工作需要,决定深入研究SQL Server的扩展事件(Extended Events/xEvents),经过资料搜索,发现国外大牛的系列文章,作为“学习”阶段,我先翻译这系列文章,后续在工作中的心 ...
随机推荐
- 第一个OC类
1.如何声明一个类 格式 注意: 1.必须以@interface开头,@end结尾 2.成员变量的声明,必须写在@interface与@end之间的大括号中 3.方法的声明必须在{}下面,不能写在{} ...
- K8s 部署 Dashboard UI 仪表板 ——让一切可视化
K8s 部署 Dashboard UI 仪表板 --让一切可视化 Dashboard 介绍 仪表板是基于Web的Kubernetes用户界面.您可以使用仪表板将容器化应用程序部署到Kuberne ...
- 用rewrite规则实现将所有到a域名的访问rewrite到b域名
1.临时重定向 1.1使用redirect实现临时重定向 # cat /apps/nginx/conf/nginx.conf ...省略... server { listen 80; server_n ...
- Kubernetes:健康检查
Blog:博客园 个人 应用在运行过程中难免会出现错误,如程序异常.软件异常.硬件故障.网络故障等.因此,系统通过一些手段来判断应用是否运行正常,这些手段称之为健康检查(诊断). 前置知识 回顾一下P ...
- Solution -「十二省联考2019」春节十二响
题目 题意简述 link. 给一棵 \(n\) 个结点的有根树,点带权.把点分为若干组,并要求同组内不存在任何祖先-后代关系.最小化每组内的最大点权之和. 数据规模 \(n\le2\tim ...
- Zookeeper 提供的API
上篇介绍了Zookeeper命令行相关的知识,本小作文介绍从另一个维度操作Node相关的内容:Zookeer的API.同样借用Zookeeper应用之一的数据注册与订阅中的案例类比命令行操作,重点介绍 ...
- Linux文件处理三剑客(grep、sed、awk)
下面所说的是Linux中最重要的三个命令在业界被称为"三剑客",它们是grep.sed.awk. 我们现在知道Linux下一切皆文件,对Linux的操作就是对文件的处理,那么怎么能 ...
- nginx拒绝国外IP访问
nginx拒绝国外IP访问方法很多,比如iptables,geoip模块,域名解析等等.这些方法不会相互冲突,可以结合起来一起使用. 今天来教大家利用两个小方法解决 域名解析禁止掉海外IP访问网站. ...
- 01_描述对象_类图(Class Diagram)
1. 作用 用于面向对象软件开发的分析和设计阶段,描述系统的静态结构. 描述类与类.类与接口.接口与接口之间的静态结构和关系,描述系统的结构化设计.最基本的元素:类.接口. 用于应用程序的一般概念 ...
- Clickhouse 分布式表&本地表
CK 分布式表和本地表 ck的表分为两种: 分布式表 一个逻辑上的表, 可以理解为数据库中的视图, 一般查询都查询分布式表. 分布式表引擎会将我们的查询请求路由本地表进行查询, 然后进行汇总最终返回给 ...