我正在编写一个半简单的数据库包装器类,并希望有一个可以自动操作的获取方法:它应该只在第一次准备每个不同的语句,然后绑定(bind)并执行查询连续调用。
我想主要问题是:如何重新准备相同的 MySql 语句,PDO 会神奇地识别该语句(因此我不必)并停止操作吗?
如果不是,我计划通过为每个不同的查询生成一个唯一的键来实现这一点,并将准备好的语句保存在数据库对象的私有(private)数组中——在它的唯一键下。我打算通过以下方式之一获取数组键(我都不喜欢)。按优先顺序:
- 让程序员在调用方法时传递一个额外的、始终相同的参数 - 类似于
basename(__FILE__, ".php") 的内容。 __LINE__
(只有在循环中调用我们的方法时,此方法才有效 - 大多数情况下都需要此功能) - 让程序员传递一个完全随机的字符串(很可能是事先生成的)作为额外参数
- 使用传递的查询本身生成 key - 获取查询的散列或类似的东西
- 通过调用
debug_backtrace
实现与第一个项目符号(上面)相同的效果
有没有人有类似的经历?虽然我正在为之工作的系统确实值得关注优化(它相当大并且每周都在增长),但也许我什么都不担心,而且做我做的事情没有性能优势'我在做什么?
最佳答案
MySQL(与大多数 DBMS 一样)将缓存准备好的语句的执行计划,因此如果用户 A 创建计划:
SELECT * FROM some_table WHERE a_col=:v1 AND b_col=:v2
(其中 v1 和 v2 是绑定(bind)变量)然后发送要由 DBMS 插值的值,然后用户 B 发送相同的查询(但具有不同的插值值)DBMS 不必重新生成计划。即是 DBMS 找到了匹配计划,而不是 PDO。
然而,这意味着数据库上的每个操作都需要至少 2 次往返(第一次呈现查询,第二次呈现绑定(bind)变量),而不是对于具有文字值的查询的单次往返,这就引入了额外的网络成本。取消引用(和维护)查询/计划缓存也需要少量成本。
关键问题是这个成本是否大于最初生成计划的成本。
虽然(根据我的经验)在 Oracle 中使用准备好的语句似乎确实有性能优势,但我不相信 MySQL 也是如此 - 然而,很大程度上取决于您的数据库结构和查询的复杂性(或者更具体地说,优化器可以找到多少个不同的选项来解决查询)。
尝试自己测量它(提示:您可能希望将慢速查询阈值设置为 0 并编写一些代码以将文字值转换回匿名表示以用于写入日志的查询)。
关于PHP PDO : how does re-preparing a statement affect performance,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2132524/