【问题标题】:MySQL prepared statement vs normal query. Gains & LossesMySQL 准备好的语句与普通查询。收益与损失
【发布时间】:2011-09-12 04:42:38
【问题描述】:

我正在更新/修改一些数据库代码,我想知道,我应该真正从使用准备好的语句中得到什么。

以这个示例代码为例:

$values = '';
for ($i = 0; $i < $count; $i++) {
    $name = mysql_real_escape_string ($list[$i][1]);
    $voc = mysql_real_escape_string ($list[$i][3]);
    $lev = $list[$it][2];
    $lev = is_numeric ($lev)? $lev : 0;

    $values .= ($values == '')? "('$name', '$voc', $lev)" : ", ('$name', '$voc', $lev)";
}
if ($values != '') {
    $core->query ("INSERT INTO onlineCList (name, voc, lev) VALUES $values;");
}

现在,除了可读性(理智)的明显提升和max_packet_size 不再成为问题的事实之外,当我重新编码以使用准备好的语句时,我是否应该期望性能发生任何变化?我正在远程连接到 MySQL 服务器,我担心发送多个小数据包会比发送一个大数据包慢得多。如果是这样的话,MySQLi/mysqlnd可以缓存这些数据包吗?

另一个例子:

$names = '';
while ($row = mysql_fetch_array ($result, MYSQL_ASSOC)) {
    $name = mysql_real_escape_string($row['name']);

    $names .= ($names == '') ? "'$name'" : ", '$name'";
}
if ($names != '') {
    $core->query ("UPDATE onlineActivity SET online = NULL WHERE name IN ($names) AND online = 1;");
}

如上所述,在重新编码后使用准备好的语句后,我是否应该期待意外?如果 MySQL 服务器必须运行一个带有大 IN 子句的查询,或者多个准备好的带有相等检查的查询 (.. WHERE name = $name AND ..),它对 MySQL 服务器有什么影响吗?

假设所有内容都已正确编入索引。

【问题讨论】:

标签: php mysql web-services


【解决方案1】:

通常,如果您只使用准备好的语句代替普通查询,它会稍微慢一些,因为查询是分两步而不是一步准备和执行的。只有在准备语句然后多次执行时,准备好的语句才会变得更快。

但是,在这种情况下,您使用的是mysql_real_escape_string,它会往返于数据库。更糟糕的是,您是在一个循环中执行此操作,因此每个查询 执行多次。因此,在这种情况下,用一条准备好的语句替换所有这些往返是双赢的。

关于您的最后一个问题,您没有理由不能像通过普通查询解析器那样对准备好的语句使用相同的查询(即,没有理由使用 IN 执行一个版本,而另一个使用一堆 OR )。 prepared statement 可以有IN (?, ?, ?),然后你只需绑定那个数量的参数。

我的建议是始终使用准备好的语句。在它们增加了边际性能开销的情况下,由于安全性(无 SQL 注入)和可读性优势,它们仍然是值得的。当然,无论何时你发现自己求助于mysql_real_escape_string,你都应该使用准备好的语句。 (对于不需要转义变量输入的简单一次性查询,它们不是绝对必要的。)

【讨论】:

  • 谢谢,我不知道mysql_real_escape_string在调用的时候实际上是和服务器通信的;我只是假设在您打开连接时存储了字符编码,mysql_real_escape_string 使用存储的信息在本地工作。
  • 是的,它应该在 PHP 文档中更突出它这样做。字节流被发送到 MySQL,它使用其字符集设置进行转义并返回转义字符串……如果您打开 MySQL 服务器的查询日志,您将看到所有这些“查询”。有旧的mysql_escape_string 在本地工作,但它不尊重字符集并且已被弃用。如果您考虑一下,这是有道理的,只有 MySQL 可以使用其精确的字符集实现来转义字符串数据。一个明显的例子是准备好的语句。
  • @joelhardi 您关于mysql_real_escape_string 的cmets 真的很有趣。这是否也适用于 mysqli 对应项?是否有任何基准可以显示开销是多少?我一直认为,当您仅计划执行一次查询时使用准备好的语句没有意义,因此有兴趣知道您需要运行多少 real_escape_strings 与执行一次的准备好的语句使后者更高效。我猜这是微优化,但同样会感兴趣。
  • mysql_real_escape_string 不会向服务器发送任何内容。考虑到实际的字符集,它会在客户端转义传递的字符串。
  • @GeorgRichter 我不知道你有什么证据证明这个说法,它绝对有。打开您的 MySQL 查询日志,您将在数据库服务器上进行查询。 This behavior is documented,您会看到mysql_real_escape_string 在没有数据库连接的情况下甚至无法运行(而是返回false)。顺便说一句,现在是 2020 年!没有人应该再使用 PHP 5.x,或者原来的 PHP MySQL 扩展,或者mysql-real-escape-string。
【解决方案2】:
  1. 准备好的语句更安全。
  2. Prepared 语句具有更好的性能。
  3. 准备好的语句写起来更方便。

你会阅读所有这些吗!

http://dev.mysql.com/tech-resources/articles/4.1/prepared-statements.html

也试试这个

Prepared Statement vs. Stored Procedure

【讨论】:

  • 2.取决于上下文。 3. 这是你的意见。
  • 虽然准备好的语句很棒(特别是如果您有用户输入等安全问题),texelate 是完全正确的,而且忘记提及它们较少便于阅读/调试。就个人而言,我很少操纵用户输入,并尽量避免准备查询,通常是因为当需要修复失败的请求时,它不会给我带来更多麻烦没有实际的 SQL 内容。它们仍然很棒,但有也理由不使用它们:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-25
  • 2019-02-06
  • 2010-12-23
  • 1970-01-01
  • 2011-09-16
  • 2014-09-27
  • 2013-04-14
相关资源
最近更新 更多