MySQL中关于prepare原理的详解

这篇文章主要介绍了mysql prepare的相关内容,包括prepare的产生,在服务器端的执行过程,以及jdbc对prepare的处理以及相关测试,需要的朋友可以了解下。希望对大家有所帮助。

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通过转义实现的,跟服务器没有关系。
硬解析的比重

   压测时通过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代码 

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。

百度文心百中 百度文心百中

百度大模型语义搜索体验中心

百度文心百中 22 查看详情 百度文心百中

   useServerPrepStmts=true, cachePrepStmts=false时服务器仍然会两次硬解析同一SQL。

   useServerPrepStmts=true, cachePrepStmts=true时服务器只会硬解析一次SQL。

   如果两次prepare之间没有ps.close();那么cachePrepStmts=true,cachePrepStmts=false也只需一次硬解析. 

   因此,客户端对同一sql,频繁分配和释放PreparedStatement对象的情况下,开启cachePrepStmts参数是很有必要的。

测试

  1)做了一个简单的测试,主要测试prepare的效果和useServerPrepStmts参数的影响.    

cnt = 5000;    // no prepare    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 " +    "parent_id = 594314511722841 or parent_id =547667559932641;";    begin = new Date();    System.out.println("begin:" + df.format(begin));    stmt = con.createStatement();    for (int i = 0; i < cnt; i++)    {            stmt.executeQuery(sql);    }     end = new Date();    System.out.println("end:" + df.format(end));    long temp = end.getTime() - begin.getTime();    System.out.println("no perpare interval:" + temp);        // test prepare        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 " +        "parent_id = 594314511722841 or parent_id =?;";    ps = con.prepareStatement(sql);    BigInteger param = new BigInteger("547667559932641");    begin = new Date();    System.out.println("begin:" + df.format(begin));    for (int i = 0; i < cnt; i++)    {      ps.setObject(1, param);      ps.executeQuery();     }     end = new Date();    System.out.println("end:" + df.format(end));    temp = end.getTime() - begin.getTime();    System.out.println("prepare interval:" + temp);

经多次采样测试结果如下

非prepare和prepare时间比useServerPrepStmts=true0.93useServerPrepStmts=false1.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原理的详解的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/389917.html

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
Apple CarPlay无法在iPhone上运行怎么办?
上一篇 2025年11月6日 15:16:07
搜狗浏览器如何翻译 搜狗浏览器怎么翻译网页
下一篇 2025年11月6日 15:16:11

相关推荐

  • MySQL表设计实战:创建一个电商订单表和商品评论表

    mysql表设计实战:创建一个电商订单表和商品评论表 在电商平台的数据库中,订单表和商品评论表是两个非常重要的表格。本文将介绍如何使用MySQL来设计和创建这两个表格,并给出代码示例。 一、订单表的设计与创建订单表用于存储用户的购买信息,包括订单号、用户ID、商品ID、购买数量、订单状态等字段。 首…

    2026年10月8日
    000
  • 如何使用MySQL数据库进行社交网络分析?

    如何使用mysql数据库进行社交网络分析? 社交网络分析(Social Network Analysis,简称SNA)是一种研究人际关系、组织结构、信息传播等社交现象的方法。随着社交媒体的兴起,对社交网络进行分析的需求越来越高。而MySQL数据库作为一个常用的数据库管理系统,也有很好的支持社交网络分…

    2026年10月8日
    000
  • TiDB相比于MySQL的事务处理能力

    tidb相比于mysql的事务处理能力 随着数据量和业务需求的不断增长,数据库的事务处理能力成为了企业和开发者关注的焦点。MySQL作为一个经典的关系型数据库管理系统,在事务处理方面有着较为成熟的解决方案。然而,随着数据规模的扩大和并发访问的增多,MySQL在某些场景下可能会遇到一些性能瓶颈。而Ti…

    2026年10月8日
    100
  • MySQL和Oracle:哪个适合中小型企业?

    mysql和oracle:哪个适合中小型企业? 引言:在信息时代中,数据库是企业不可或缺的一部分。随着中小型企业的发展,选择合适的数据库管理系统(Database Management System,DBMS)成为了一项重要的决策。MySQL和Oracle作为数据库领域的两大巨头,一直备受关注。本文…

    2026年10月8日
    200
  • MySQL和Oracle:对于复制和冗余的可行性对比

    mysql和oracle:对于复制和冗余的可行性对比 摘要:数据库复制和数据冗余是现代数据库管理系统中常见的技术手段。本文将重点比较MySQL和Oracle这两种主流数据库管理系统在复制和冗余方面的可行性。我们将关注以下几个方面进行比较:复制类型、冗余策略、性能和可靠性。 复制类型:MySQL提供了…

    2026年10月8日
    200
  • TiDB与MySQL的跨数据中心复制能力对比

    tidb与mysql的跨数据中心复制能力对比 简介:TiDB是一种分布式关系型数据库,可以通过跨数据中心复制来实现高可用性和灾备容灾。而MySQL也提供了一些方式来实现跨数据中心复制。本文将比较TiDB和MySQL在跨数据中心复制能力方面的异同,并给出相应代码示例。 一、TiDB的跨数据中心复制能力…

    2026年10月8日
    100
  • MySQL和Oracle:在多用户并发环境中的性能表现

    mysql和oracle:在多用户并发环境中的性能表现 引言:在当今的互联网时代,数据库作为核心的存储和管理数据的系统非常重要。对于开发者和管理员来说,选择一个合适的数据库管理系统(DBMS)对于系统的性能至关重要。MySQL和Oracle作为最流行的关系型数据库管理系统之一,它们在多用户并发环境中…

    2026年10月7日
    500
  • PHP如何处理数据库事务回滚_PHP实现mysql事务回滚的步骤

    首先关闭自动提交并开启事务,然后执行SQL操作,若全部成功则提交,否则回滚。具体步骤为:使用PDO的beginTransaction()方法启动事务,执行SQL时捕获异常,无错误调用commit(),有异常则rollback(),最后确保事务结束。关键在于启用异常模式和正确处理异常,防止数据不一致。…

    2026年10月7日
    200
  • MySQL和Oracle:对于数据压缩和存储空间利用率的比较

    mysql和oracle:对于数据压缩和存储空间利用率的比较 导言:在今天的数据驱动型世界中,数据存储和处理的效率对于企业来说非常重要。数据压缩和存储空间利用率是数据库管理系统中一个重要的话题。MySQL和Oracle作为两个主流的关系型数据库管理系统,都提供了数据压缩的功能。本文将对比MySQL和…

    2026年10月7日
    100
  • MySQL和MongoDB:在物联网应用中的比较

    mysql和mongodb:在物联网应用中的比较 摘要:随着物联网应用的快速发展,数据库选择变得越来越重要。本文将比较两个常见的数据库系统MySQL和MongoDB在物联网应用中的优劣,并通过代码示例展示它们的不同之处。 引言:物联网应用的快速发展给数据库系统提出了新的挑战。在处理大量实时数据、高并…

    2026年10月7日
    100
  • 如何监视MySQL数据库的查询性能?

    如何监视mysql数据库的查询性能? 为了优化MySQL数据库的查询性能,我们需要了解查询的执行效率及其消耗的资源。在实际应用中,可以采用多种方法来监视和分析MySQL数据库的查询性能,从而找出性能瓶颈并进行优化。 一、使用Explain语句分析查询计划 Explain语句可以展示MySQL数据库执…

    2026年10月7日
    100
  • 如何用Java开发数字孪生?ThingJS三维可视化

    如何用Java开发数字孪生?ThingJS三维可视化如何用Java开发数字孪生?ThingJS三维可视化如何用Java开发数字孪生?ThingJS三维可视化如何用Java开发数字孪生?ThingJS三维可视化

    要开发java数字孪生并结合thingjs三维可视化,核心步骤如下:1. 数据采集与处理:使用java通过mqtt、http等协议连接传感器设备,进行数据清洗、转换,并存储至数据库;2. 三维模型构建与集成:在thingjs中导入obj、fbx等格式模型,优化后绑定java处理的数据并设计交互;3.…

    2026年10月7日 • 用户投稿
    100
  • MySQL测试框架MTR:保障数据库可靠性与安全性的利器

    mysql测试框架mtr:保障数据库可靠性与安全性的利器 随着互联网应用的快速发展,数据库成为了现代信息系统中不可或缺的重要组成部分。而对于数据库的可靠性与安全性,更是每个开发者和管理员都需要考虑的关键问题。为了保障数据库的稳定性与安全性,MySQL提供了一个强大的测试框架MTR(MySQL Tes…

    2026年10月7日
    400
  • 如何使用MySQL数据库进行文本分析?

    如何使用mysql数据库进行文本分析? 随着大数据时代的到来,文本分析成为了一项非常重要的技术。而MySQL作为一种流行的关系型数据库,也可以用于进行文本分析。本文将介绍如何使用MySQL数据库进行文本分析,并提供相应的代码示例。 创建数据库和表 首先,我们需要创建一个MySQL数据库和表来存储文本…

    2026年10月7日
    200
  • 如何使用MySQL中的LEFT函数截取字符串的左边部分

    如何使用mysql中的left函数截取字符串的左边部分 在数据库管理系统中,经常会遇到需要从字符串中截取某部分的情况。MySQL提供了许多内置的字符串函数,其中包括LEFT函数,它可以用于截取字符串的左边部分。 LEFT函数的语法如下: LEFT(str, length) 其中,str是要被截取的字…

    2026年10月7日
    000
  • 数据库容量规划和扩展:MySQL vs. PostgreSQL

    数据库容量规划和扩展:mysql vs. postgresql 引言:随着互联网的快速发展和大数据时代的到来,数据库的容量规划和扩展变得越来越重要。MySQL和PostgreSQL是两个流行的关系型数据库管理系统(RDBMS),它们在数据库容量规划和扩展方面有着不同的特点和适用场景。本文将对这两个数…

    2026年10月7日
    300
  • 修改MySQL错误日志编码避免记录乱码信息

    mysql错误日志出现乱码的主要原因是日志编码与系统或查看工具不一致,解决方法如下:1. 在my.cnf或my.ini中配置character-set-server=utf8mb4和collation-server=utf8mb4_unicode_ci,统一数据库字符集以影响日志输出;2. 确保终端…

    2026年10月7日
    100
  • MySQL和Oracle:对于数据安全和隐私保护的措施对比

    mysql和oracle:对于数据安全和隐私保护的措施对比 摘要:随着数字化时代的到来,数据安全和隐私保护变得至关重要。MySQL和Oracle是两个常用的关系型数据库管理系统,它们在数据安全性和隐私保护方面采取了不同的措施。本文将对两者进行对比,并通过代码示例来展示它们的安全特性。 引言:随着互联…

    2026年10月7日
    1200
  • 如何使用MySQL数据库进行机器学习任务?

    如何使用mysql数据库进行机器学习任务? 随着大数据时代的到来,机器学习算法在各个领域得到了广泛应用。而作为数据存储和管理的核心工具之一,MySQL数据库也有着重要的地位。那么,如何使用MySQL数据库进行机器学习任务呢?本文将向读者介绍使用MySQL数据库进行机器学习任务的常用方法,并提供相应的…

    2026年10月7日
    100
  • 如何使用MySQL中的CONV函数将一个数值转换为不同的进制

    如何使用mysql中的conv函数将一个数值转换为不同的进制 导言:在数据库中,常常需要将数值在不同的进制之间进行转换。MySQL提供了一个非常方便的函数CONV,可以快速实现数值的进制转换。本文将详细介绍如何使用CONV函数,以及提供了一些代码示例。 一、CONV函数概述CONV函数是MySQL提…

    2026年10月7日
    100

发表回复

登录后才能评论
关注微信