与 PDOStatement::bindParam() 相比,使用 PHP mysqli_stmt::bind_param() 时,MYSQL 查询性能非常差

MYSQL query performance very poor when using PHP mysqli_stmt::bind_param() compared to PDOStatement::bindParam()

提问人:gvn 提问时间:8/24/2022 最后编辑:gvn 更新时间:8/26/2022 访问量:142

问:

我在运行以下命令时遇到了与使用 PHP 相关的性能问题:mysqli_stmt::bind_param()

$sql = "select ts from scans where sessionid = ? order by id desc limit 1";
$stmt = $db->prepare($sql);

$stmt->bind_param("i", $row_sid );

$stmt->execute();

$result = $stmt->get_result()->fetch_array(); 

$stmt->close();

对于表中超过 20000 个点的最坏情况,此查询需要 2 秒,但这仅在使用 时发生。scansrow_sid = 10mysqli_stmt::bind_param()

如果我将查询本身作为:

select ts from scans where sessionid = 10 order by id desc limit 1;

它在 0.016 秒后返回。

如果我不使用 bind 参数,也一样:

$sql = "select ts from scans where sessionid = 10 order by id desc limit 1";
$stmt = $db->prepare($sql);

$stmt->execute();
$result = $stmt->get_result()->fetch_array(); 

$stmt->close();

这也以毫秒为单位返回。

按照扫描表详细信息操作:

SHOW CREATE TABLE

scans | CREATE TABLE `scans` (
  `id` int NOT NULL AUTO_INCREMENT,
  `lid` int DEFAULT NULL,
  `devid` int DEFAULT NULL,
  `sessionid` int DEFAULT NULL,
  `ts` int DEFAULT NULL,
  `irpwr` double DEFAULT NULL,
  `ir_v` double DEFAULT NULL,
  `ir_i` double DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `scans_sessionid` (`sessionid`),
  KEY `scans_devlid` (`devid`,`lid`),
  KEY `scans_ts` (`ts`),
  KEY `scans_lid` (`lid`)
) ENGINE=InnoDB AUTO_INCREMENT=43769072 DEFAULT CHARSET=utf8

编辑:

我使用 PDO 而不是 mysqli 进行了测试,性能得到了显着提高,无论是使用还是返回都接近直接查询速度。虽然,我没有找到任何显示性能差异原因的信息,因为 mysqli 已被证明在基准测试中更快。bindValue()bindParam()

我可能遇到了一个我不明白的错误。

php mysql mysqli pdo

评论

0赞 ADyson 8/24/2022
Even though I fixed the sessionid as 10 which is the biggest query...可能是因为它只执行相同的查询 40 次,所以它只需要运行一次,然后每次都返回一些缓存数据。
0赞 ADyson 8/24/2022
表上有索引吗?
0赞 rickdenhaan 8/24/2022
It returns in milliseconds.-- 多少毫秒?如果执行查询 40 次,需要 2 秒,则解决方案平均每个查询需要 50 毫秒。bind_param
1赞 rickdenhaan 8/24/2022
执行单个查询 () 可能更有效。where sessionid in (<your 40 ids>)
1赞 Your Common Sense 8/26/2022
相关新闻: stackoverflow.com/questions/72989927/... 和 stackoverflow.com/questions/73210332/...

答:

-1赞 Rick James 8/26/2022 #1

为了“证明”“bind”是错误的,请在PHP代码中加入以分离出对bind的调用。microtime(true)

若要对任何 SQL 查询进行计时,请运行两次。有多个缓存会干扰获取实际时间。

  • 如果数据尚未缓存在buffer_pool(或其他 RAM 缓存)中,则首次运行会因为 I/O 而变慢;第二个是对查询的生产使用情况的现实估计。

  • 如果“查询缓存”为 ON,则无论查询有多复杂,第二次都将约为 1 毫秒。QC正在消失;计划将来将其移除。同时,做然后计时。SELECT SQL_NO_CACHE ...

回到具体查询...

select  ts
    from  scans
    where  sessionid = ?
    order by  id desc
    limit  1

将运行得更快

INDEX(session_id, id, ts)

添加时,还要删除现有的 INDEX(session_id) 作为冗余。