参考简书/知乎 大神回答,并截取了个人认为的重点内容:
1.SQL预编译
一、sql预编译:
数据库接收到sql语句后,需要词法/语法解析,优化sql语句,制定执行计划。多数情况下,相同的sql语句可能只是传入参数不同(如where条件后的值不同...)。
如果每次都需要经过上面的词法/语法解析、语句优化、制定执行计划等,则效率就明显不行了。所以预编译的优势就体现出来了。预编译语句在被MySQL编译器编译后,执行代码会被缓存下来。那么下次调用时,只要是相同的预编译语句就再不需要编译,只要将参数直接传入编译过的语句执行代码中即可。
二、实现:
预编译语句就是将这类语句中的值用占位符替代(例如问号:?)
,可以视为将sql语句模板化或者说参数化
。一次编译、多次运行,省去了解析优化等过程。
三、sql预编译的作用:
- 预编译阶段可以优化 sql 的执行:预编译之后的 sql 多数情况下可以直接执行,DBMS 不需要再次编译,越复杂的sql,编译的复杂度将越大。预编译阶段可以合并多次操作为一个操作,从而提升性能。
- 防止SQL注入:使用预编译,而其后注入的参数将
不会再进行SQL编译
。也就是说其后注入进来的参数系统将不会认为它会是一条SQL命令,而默认其是一个参数
,参数中的or或者and 等就不是SQL语法关键字了,而是被当做纯数据处理。
补充:关于MySQL预编译语句超过上限的报错:
Can’t create more than max_prepared_stmt_count statements (current value: 16382)
MySQL中的 max_prepared_stmt_count 变量是用来控制全局最大存储的预编译语句数,参考:
记录go数据库操作的bug——max_prepared_stmt_count,附分析过程
MySQL 查看/设置 max_prepared_stmt_count 的值:
show variables like '%max_prepared_stmt_count%';
set global max_prepared_stmt_count = 65536;
关于MySQL预编译的使用建议:
经过实际测试,对于频繁使用的语句,使用服务端 “预编译 + 缓存效率” 还是能够得到可观的提升的。但是对于不频繁使用的语句,服务端预编译本身会增加额外的耗时,还会增加MySQL的使用内存。因此在实际开发中可以视情况定夺使用本地预编译还是服务端预编译,以及哪些sql语句不需要开启预编译等。