MySQL数据库中预处理prepared statement性能测试的示例

24次阅读
没有评论

共计 3333 个字符,预计需要花费 9 分钟才能阅读完成。

自动写代码机器人,免费开通

丸趣 TV 小编给大家分享一下 MySQL 数据库中预处理 prepared statement 性能测试的示例,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

1、预处理干了什么

当我们提交一条数据库语句时,语句到达数据库服务那边,数据库服务需要解析这条 sql 语句,比如说语法检查,查询条件先后优化,然后才执行。对于预处理,简单来说就是把客户端与数据库服务原本一次交互的分成两次。首先,提交数据库语句,让数据库服务先解析这条语句。其次,提交参数,调用语句并执行。这样对于多次重复执行的语句来说,可以提交并解析一次数据库语句就可以了,然后不断的调用刚刚解析过得语句并执行。这样就省去了多次解析同一条语句的时间。从而达到提高效率的目的。

预处理语句支持占位符(place holder), 通过绑定占位符的方式提交参数。一个非常重要的一点是,能与占位符绑定的只能是值,而不能是 sql 语句的一些关键词。例如语句:“select * from student where student.id = ?”。如果放入占位符(?)中的是“1 or 1=1”,那么“1 or 1=1”就会被当成一个值,即用 “ 符号包括起来,最终这条非法的语句就出错了。从而达到放 sql 注入的漏洞(sql injestion)。

预处理机制主要的三步骤:

1、将语句进行预处理

2、执行语句

3、析构掉预处理语句。

2、关于 `performance_schema`.`prepared_statements_instances` 表的介绍

运行 sql 脚本:show global variable like‘%prepare%’。可以看到一个叫‘performance_schema_max_prepared_statement_instances’的系统变量。其值为 0 表示不启用预处理语句性能数据记录表 `performance_schema`.`prepared_statements_instances`;- 1 表示记录的数量动态处理;其他正整数值则表示 performance_schema_max_prepared_statement_instances 记录的最大条数。

表 `performance_schema`.`prepared_statements_instances` 又是什么呢?它是用来记录预处理语句的一些基本信息和性能数据。比如预处理语句的 ID,预处理语句的名字,预处理语句的具体语句内容,预处理语句被执行的次数,每次执行耗时,每条预处理语句所属的线程 id 等。当我们创建一条预处理语句时,就会插入一条数据到这张表里。预处理语句是基于连接的,连接断开,则预处理语句自动删除。但 `performance_schema`.`prepared_statements_instances` 表是全局的,它与数据库连接没关系。有了这些数据,我们就可以知道,1、代码中执行的语句是否真的做了预处理,2、通过了解预处理语句的执行情况来决定业务中是否需要把一个语句进行预处理。

3、qt prepare 函数说明

根据我自己本身的项目需求,这次测试的客户端代码使用的是 Qt。这里记录一个关键的函数:QSqlQuery 类的 prepare 函数。调用 prepare 函数即是向数据库提交一个创建预处理语句的命令。意味着调用期间,是会与数据库服务进行一次交互的。需要注意的是,当同一个 QSqlQuery 类对象调用第二次 prepare 时,会将第一次调用 prepare 创建的预处理语句删除掉,然后再创建一条预处理语句,即便是这两条预处理语句是一模一样的。在调用 QSqlQuery 的 exec 函数时,也会将 QSqlQuery 先前创建的预处理语句删除掉。所以在查询结束,关闭掉连接,或者查询又执行了其他语句,从而导致 `performance_schema`.`prepared_statements_instances` 表没有相关预处理语句的记录,就会误认为预处理语句创建失败。其实 Qt 的这种做法,也省去了要我们人为的删除预处理语句。

4、实验猜想

常规执行的语句和预处理后执行的语句不同点在于,在多次执行的情况下,预处理语句只需解析一次 sql 语句,而之后多花时间在传输参数和绑定参数上。预处理语句在返回结果时,使用的是二进制传输协议,而普通语句使用的是文本格式的传输协议。因此我们做出以下猜想并验证。

1、如果执行的是简单语句,那么普通执行和预处理执行性能上差别不大。预处理语句在重复执行复杂的语句情况下才展现出优势。

2、在查询结果集是大数据量的情况下,预处理语句会展现出性能优势。

5、实验数据记录  

序号是否预处理语句是否远程数据库返回数据量每次实验语句执行总次数三次实验平均总耗时 / 单位毫秒 1 是 select * from task where task.taskId in (?) 是 10001000698222 否 select * from task where task.taskId in (arr) 是 10001000667783 是 select * from task where task.taskId = ? 是 1100012604 否 select * from task where task.taskId = id 是 110009515 是 select * from task a LEFT JOIN task_file b ON a.taskId = b.task_id where a.taskName like %s% and b.file_id 100000 and b.file_id 200000  and a.taskId =?是 2100021306 否 select * from task a LEFT JOIN task_file b ON a.taskId = b.task_id where a.taskName like %s% and b.file_id 100000 and b.file_id 200000  and a.taskId = 32327 是 2100014807 是 select * from task where task.taskId in (?) 否 10001000570518 否 select * from task where task.taskId in (arr) 否 10001000562359 是 select * from task where task.taskId = ? 否 1100021710 否 select * from task where task.taskId = id 否 1100020411 是 select * from task a LEFT JOIN task_file b ON a.taskId = b.task_id where a.taskName like %s% and b.file_id 100000 and b.file_id 200000  and a.taskId =?否 2100036612 否 select * from task a LEFT JOIN task_file b ON a.taskId = b.task_id where a.taskName like %s% and b.file_id 100000 and b.file_id 200000  and a.taskId = 32327 否 21000380

6、结论

实验的数据结果和我预期的相差有点儿大,但经过反复检查测试代码和测试过程,确认测试本身应该没有问题。尊重实验数据,我们得出以下结论:

1、通过实验 5 和实验 6 对比,实验 11 和实验 12 对比,可得猜想 1 是错误的。结论应该是:MySQL 预处理和常规查询在简单语句和复杂语句下,都没有显著性的性能差别。

2、通过实验 1 和实验 2 对比,实验 7 和实验 8 对比,可得猜想 2 是错误的。结论应该是:MySQL 预处理和常规查询的结果在数据传输上没有显著性的性能差距。

       3、此外,对比远程数据库和本地数据库实验数据。可得结论:MySQL 数据库在本地会给数据操作带来显著性的性能提高。

以上是“MySQL 数据库中预处理 prepared statement 性能测试的示例”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注丸趣 TV 行业资讯频道!

向 AI 问一下细节

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-12-04发表,共计3333字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)