mysql prepare原理
注:2013年的老文章
Prepare的作用
Prepare SQL产生的原因。首先从mysql服务器执行sql的过程开始讲起,SQL执行过程包括以下阶段 词法分析->语法分析->语义分析->执行计划优化->执行。词法分析->语法分析这两个阶段我们称之为硬解析。词法分析识别sql中每个词,语法分析解析SQL语句是否符合sql语法,并得到一棵语法树(Lex)。对于只是参数不同,其他均相同的sql,它们执行时间不同但硬解析的时间是相同的。而同一SQL随着查询数据的变化,多次查询执行时间可能不同,但硬解析的时间是不变的。对于sql执行时间较短,sql硬解析的时间占总执行时间的比率越高。而对于淘宝应用的绝大多数事务型SQL,查询都会走索引,执行时间都比较短。因此淘宝应用db sql硬解析占的比重较大。
Prepare的出现就是为了优化硬解析的问题。Prepare在服务器端的执行过程如下
1) Prepare 接收客户端带”?”的sql, 硬解析得到语法树(stmt->Lex), 缓存在线程所在的preparestatement cache中。此cache是一个HASH MAP. Key为stmt->id. 然后返回客户端stmt->id等信息。
2) Execute 接收客户端stmt->id和参数等信息。注意这里客户端不需要再发sql过来。服务器根据stmt->id在preparestatement cache中查找得到硬解析后的stmt, 并设置参数,就可以继续后面的优化和执行了。
Prepare在execute阶段可以节省硬解析的时间。如果sql只执行一次,且以prepare的方式执行,那么sql执行需两次与服务器交互(Prepare和execute), 而以普通(非prepare)方式,只需要一次交互。这样使用prepare带来额外的网络开销,可能得不偿失。我们再来看同一sql执行多次的情况,比如以prepare方式执行10次,那么只需要一次硬解析。这时候 额外的网络开销就显得微乎其微了。因此prepare适用于频繁执行的SQL。
Prepare的另一个作用是防止sql注入,不过这个是在客户端jdbc通过转义实现的,跟服务器没有关系。
硬解析的比重
交易买家库 tcbyer压测时,通过perf 得到的结果。
硬解析相关的函数比重都比较靠前(MYSQLparse 4.93%, lex_one_token 1.79%, lex_start 1.12%)总共接近8%。因此,服务器使用prepare是可以带来较多的性能提升的。
jdbc与prepare
jdbc服务器端的参数:
useServerPrepStmts:默认为false. 是否使用服务器prepare开关
jdbc客户端参数:
cachePrepStmts:默认false.是否缓存prepareStatement对象。每个连接都有一个缓存,是以sql为唯一标识的LRU cache. 同一连接下,不同stmt可以不用重新创建prepareStatement对象。
prepStmtCacheSize:LRU cache中prepareStatement对象的个数。一般设置为最常用sql的个数。
prepStmtCacheSqlLimit:prepareStatement对象的大小。超出大小不缓存。
Jdbc对prepare的处理过程:
useServerPrepStmts=true时Jdbc对prepare的处理
1) 创建PreparedStatement对象,向服务器发送COM_PREPARE命令,并传送带问号的sql. 服务器返回jdbc stmt->id等信息
2) 向服务器发送COM_EXECUTE命令,并传送参数信息。
useServerPrepStmts=false时Jdbc对prepare的处理
1) 创建PreparedStatement对象,此时不会和服务器交互。
2) 根据参数和PreparedStatement对象拼接完整的SQL,向服务器发送QUERY命令
我们再看参数cachePrepStmts打开时在useServerPrepStmts为true或false时,均缓存PreparedStatement对象。只不过useServerPrepStmts为的true缓存PreparedStatement对象包含服务器的stmt->id等信息,也就是说如果重用了PreparedStatement对象,那么就省去了和服务器通讯(COM_PREPARE命令)的开销。而useServerPrepStmts=false是,开启cachePrepStmts缓存PreparedStatement对象只是简单的sql解析信息,因此此时开启cachePrepStmts意义不是太大。
我们来开看一段java代码
1
2
3
4
5
6
7
8
9
10
11
|
Connection con = null ;
PreparedStatement ps = null ;
String sql = "select * from user where id=?" ;
ps = con.prepareStatement(sql);
ps.setInt( 1 , 1 );
ps.executeQuery();
ps.close();
ps = con.prepareStatement(sql);
ps.setInt( 1 , 3 );
ps.executeQuery();
ps.close();
|
这段代码在同一会话中两次prepare执行同一语句,并且之间有ps.close();
useServerPrepStmts=false时,服务器会两次硬解析同一SQL。
useServerPrepStmts=true, cachePrepStmts=false时服务器仍然会两次硬解析同一SQL。
useServerPrepStmts=true, cachePrepStmts=true时服务器只会硬解析一次SQL。
如果两次prepare之间没有ps.close();那么cachePrepStmts=true,cachePrepStmts=false也只需一次硬解析.
因此,客户端对同一sql,频繁分配和释放PreparedStatement对象的情况下,开启cachePrepStmts参数是很有必要的。
测试
1)做了一个简单的测试,主要测试prepare的效果和useServerPrepStmts参数的影响.
1
|
<span style= "font-family: 宋体, SimSun; font-size: 14px;" > cnt = 5000;<br> // no prepare <br> String sql = "select biz_order_id,out_order_id,seller_nick,buyer_nick,seller_id,buyer_id,auction_id,auction_title,auction_price,buy_amount,biz_type,sub_biz_type,fail_reason,pay_status,logistics_status,out_trade_status,snap_path,gmt_create,status,ifnull(buyer_rate_status, 4) buyer_rate_status from tc_biz_order_0030 where " +<br> "parent_id = 594314511722841 or parent_id =547667559932641;" ;<br><br> begin = new Date ();<br> System. out .println( "begin:" + df.format( begin ));<br> <br> stmt = con.createStatement();<br> for ( int i = 0; i < cnt; i++)<br> { <br> stmt.executeQuery(sql);<br> } <br> <br> end = new Date ();<br> System. out .println( "end:" + df.format( end ));<br> <br> long temp = end .getTime() - begin .getTime();<br> System. out .println( "no perpare interval:" + temp );<br> <br> <br> // test prepare <br> sql = "select biz_order_id,out_order_id,seller_nick,buyer_nick,seller_id,buyer_id,auction_id,auction_title,auction_price,buy_amount,biz_type,sub_biz_type,fail_reason,pay_status,logistics_status,out_trade_status,snap_path,gmt_create,status,ifnull(buyer_rate_status, 4) buyer_rate_status from tc_biz_order_0030 where " +<br> "parent_id = 594314511722841 or parent_id =?;" ;<br> ps = con.prepareStatement(sql);<br> BigInteger param = new BigInteger( "547667559932641" );<br> <br> begin = new Date ();<br> System. out .println( "begin:" + df.format( begin ));<br> <br> for ( int i = 0; i < cnt; i++)<br> {<br> ps.setObject(1, param);<br> ps.executeQuery(); <br> } <br> <br> end = new Date ();<br> System. out .println( "end:" + df.format( end ));<br> <br> temp = end .getTime() - begin .getTime();<br> System. out .println( "prepare interval:" + temp );<br></span>
|
经多次采样测试结果如下:
非prepare和prepare时间比 | |
useServerPrepStmts=true | 0.93 |
useServerPrepStmts=false | 1.01 |
结论:
useServerPrepStmts=true时,prepare提升7%;
useServerPrepStmts=false时,prepare与非prepare性能相当。
如果将语句简化为select * from tc_biz_order_0030 where parent_id =?。那么测试的结论useServerPrepStmts=true时,prepare仅提升2%;sql越简单硬解析的时间就越少,prepare的提升就越少。
注意:这个测试是在单个连接,单条sql的理想情况下进行的,线上会出现多连接多sql,还有sql执行频率,sql的复杂程度等不同,因此prepare的提升效果会随具体环境而变化。
2)prepare 前后的perf top 对比
以下为非prepare
6.46% mysqld mysqld [.] _Z10MYSQLparsePv
3.74% mysqld libc-2.12.so [.] __memcpy_ssse3
2.50% mysqld mysqld [.] my_hash_sort_utf8
2.15% mysqld mysqld [.] cmp_dtuple_rec_with_match
2.05% mysqld mysqld [.] _ZL13lex_one_tokenPvS_
1.46% mysqld mysqld [.] buf_page_get_gen
1.34% mysqld mysqld [.] page_cur_search_with_match
1.31% mysqld mysqld [.] _ZL14build_templateP19row_prebuilt_structP3THDP5TABLEj
1.24% mysqld mysqld [.] rec_init_offsets
1.11% mysqld libjemalloc.so.1 [.] free
1.09% mysqld mysqld [.] rec_get_offsets_func
1.01% mysqld libjemalloc.so.1 [.] malloc
0.96% mysqld libc-2.12.so [.] __strlen_sse42
0.93% mysqld mysqld [.] _ZN4JOIN8optimizeEv
0.91% mysqld mysqld [.] _ZL15get_hash_symbolPKcjb
0.88% mysqld mysqld [.] row_search_for_mysql
0.86% mysqld [kernel.kallsyms] [k] tcp_recvmsg
以下为perpare
3.46% mysqld libc-2.12.so [.] __memcpy_ssse3
2.32% mysqld mysqld [.] cmp_dtuple_rec_with_match
2.14% mysqld mysqld [.] _ZL14build_templateP19row_prebuilt_structP3THDP5TABLEj
1.96% mysqld mysqld [.] buf_page_get_gen
1.66% mysqld mysqld [.] page_cur_search_with_match
1.54% mysqld mysqld [.] row_search_for_mysql
1.44% mysqld mysqld [.] btr_cur_search_to_nth_level
1.41% mysqld libjemalloc.so.1 [.] free
1.35% mysqld mysqld [.] rec_init_offsets
1.32% mysqld [kernel.kallsyms] [k] kfree
1.14% mysqld libjemalloc.so.1 [.] malloc
1.08% mysqld [kernel.kallsyms] [k] fget_light
1.05% mysqld mysqld [.] rec_get_offsets_func
0.99% mysqld mysqld [.] _ZN8Protocol24send_result_set_metadataEP4ListI4ItemEj
0.90% mysqld mysqld [.] sync_array_print_long_waits
0.87% mysqld mysqld [.] page_rec_get_n_recs_before
0.81% mysqld mysqld [.] _ZN4JOIN8optimizeEv
0.81% mysqld libc-2.12.so [.] __strlen_sse42
0.78% mysqld mysqld [.] _ZL20make_join_statisticsP4JOINP10TABLE_LISTP4ItemP16st_dynamic_array
0.72% mysqld [kernel.kallsyms] [k] tcp_recvmsg
0.63% mysqld libpthread-2.12.so [.] __pthread_getspecific_internal
0.63% mysqld [kernel.kallsyms] [k] sk_run_filter
0.60% mysqld mysqld [.] _Z19find_field_in_tableP3THDP5TABLEPKcjbPj
0.60% mysqld mysqld [.] page_check_dir
0.57% mysqld mysqld [.] _Z16dispatch_command19enum_server_commandP3THDP
对比可以发现 MYSQLparse lex_one_token在prepare时已优化掉了。
思考
1 开启cachePrepStmts的问题,前面谈到每个连接都有一个缓存,是以sql为唯一标识的LRU cache. 在分表较多,大连接的情况下,可能会个应用服务器带来内存问题。这里有个前提是ibatis是默认使用prepare的。 在mybatis中,标签statementType可以指定某个sql是否是使用prepare.
statementType Any one of STATEMENT, PREPARED or CALLABLE. This causes MyBatis to use Statement, PreparedStatement orCallableStatement respectively. Default: PREPARED.
这样可以精确控制只对频率较高的sql使用prepare,从而控制使用prepare sql的个数,减少内存消耗。遗憾的是目前集团貌似大多使用的是ibatis 2.0版本,不支持statementType
标签。
2 服务器端prepare cache是一个HASH MAP. Key为stmt->id,同时也是每个连接都维护一个。因此也有可能出现内存问题,待实际测试。如有必要需改造成Key为sql的全局cache,这样不同连接的相同prepare sql可以共享。
3 oracle prepare与mysql prepare的区别:
mysql与oracle有一个重大区别是mysql没有oracle那样的执行计划缓存。前面我们讲到SQL执行过程包括以下阶段 词法分析->语法分析->语义分析->执行计划优化->执行。oracle的prepare实际上包括以下阶段:词法分析->语法分析->语义分析->执行计划优化,也就是说oracle的prepare做了更多的事情,execute只需要执行即可。因此,oracle的prepare比mysql更高效。
mysql prepare原理相关推荐
- mysql prepare原理,mysql Prepared Statements 原理介绍与优点 | 学步园
一:介绍从 5.1开始,mysql支持服务器端的Prepared Statements,他使用在client/server更有优势的binary protocol,(mysql的传统的协议中,再把数据 ...
- mysql xid原理_MySQL数据库分布式事务XA实现原理分析
[IT168 技术]MySQL XA原理 MySQL XA分为两类,内部XA与外部XA;内部XA用于同一实例下跨多个引擎的事务,由大家熟悉的Binlog作为协调者;外部XA用于跨多MySQL实例的分布 ...
- mysql prepare有什么用_mysql中的prepare介绍和应用
简单的用set或者declare语句定义变量,然后直接作为sql的表名是不行的,mysql会把变量名当作表名.在其他的sql数据库中也是如此,mssql的解决方法是将整条sql语句作为变量,其中穿插变 ...
- mysql prepare 存储过程_mysql prepare 存储过程使用
语法 [sql] PREPARE statement_name FROM sql_text /*定义*/ EXECUTE statement_name [USING variable [,variab ...
- mysql json匹配key为数值_干货篇:一篇文章让你——《深入解析MySQL索引原理》
概述 最近一段时间重新深入研究了一遍MySQL的内容,今天主要分享分析MySQL索引原理,后续会输出一些关于MySQL方面的干货,希望各位小伙伴喜欢. 一.什么是索引.为什么要建立索引? 关于索引的理 ...
- 转:MySQL索引原理及慢查询优化
来自:http://tech.meituan.com/mysql-index.html MySQL凭借着出色的性能.低廉的成本.丰富的资源,已经成为绝大多数互联网公司的首选关系型数据库.虽然性能出色, ...
- 赠书:深入理解MySQL主从原理
根据经验,想要快速学习一门技术有3种方式. 第一种方式是通过代码来理解它的实现,反推它的逻辑. 这种方式的难度很大,而且起点相对高,能够沉浸其中的人非常少,过程相对来说是苦闷的,但如果能够沉下心来看代 ...
- MySQL主从原理,基于快速学习一门技术的3种方式!
根据经验,想要快速学习一门技术有3种方式. 第一种方式是通过代码来理解它的实现,反推它的逻辑. 这种方式的难度很大,而且起点相对高,能够沉浸其中的人非常少,过程相对来说是苦闷的,但如果能够沉下心来看代 ...
- mysql主从复制原理 简书_mysql主从复制,从原理讲到安装配置,全干货
0.为什么需要主从复制? 1.在业务复杂的系统中,有这么一个情景,有一句sql语句需要锁表,导致暂时不能使用读的服务,那么就很影响运行中的业务,使用主从复制,让主库负责写,从库负责读,这样,即使主库出 ...
最新文章
- 舵机任意角度程序_真香!!!飞特发布性价比超高的19kg磁编码360°双轴串口总线舵机STS3215...
- PHP ----MySQL 数据库
- Maven私服安装及配置——(十二)
- ArrayAdapter的使用
- MTK+Android编译
- 7、Java并发性和多线程-如何创建并运行线程
- C语言高级编程:二维数组、指针的指针、数组指针、指针数组
- UWidgetBlueprintLibrary
- Java读书笔记(8)-单例模式
- DataGrid添加CheckBox(下拉列表)
- Python使用Mysql官方驱动(取出dict类型的数据)
- Java编程实现三种等级的扫雷游戏(完整版)
- AtCoder Beginner Contest 262 部分题解
- 计算机网络军训口号,关于物联网的军训口号
- 【报告分享】2021快手内容生态半年报-快手(附下载)
- c语言 运行经过八个翻译阶段,GitHub - BUAA-SE-Compiling/miniplc0-handbook: miniplc0 指导书...
- gromcas 分析NAMD轨迹文件dcd
- 研究生招生信息网服务器异常,2012研究生网上报名常见问题汇总
- TS之namespace与module
- Python细枝末节个人知识记录
热门文章
- 快速人体姿态估计--Pose Proposal Networks
- Windows系统下MySQL安装详细教程(解决MySQL服务无法启动)
- LeetCode 92. Reverse Linked List II--Python 解法--反转部分链表--笔试算法题
- WSL的openssh-server使用报错:Could not load host key: /etc/ssh/ssh_host_rsa_key
- 优先深度搜索判断曲线相交_程序员必知的十大基础实用算法之-DFS(深度优先搜索)...
- linux下php连接mysql数据库_Linux下PHP连接Oracle数据库
- matlab fft simulink,在Simulink中复制MATLAB的FFT?
- java获取真实ip工具类
- python自动整理文件夹_计算机文件和文件夹的Python自动管理,自动化,电脑,及
- 奔腾微型计算机采用的微处理器的型号,“奔腾”微型计算机采用的微处理器的型号是()。...