简体   繁体   中英

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

I am having a performance issue related to using PHP mysqli_stmt::bind_param() when running the following:

$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();

This query is taking 2 seconds for the worse case where scans table have over 20000 points with the respective row_sid = 10 , but this only happens when using mysqli_stmt::bind_param() .

If I run the query by itself as:

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

It returns in 0.016 seconds.

The same if I do not use bind parameter:

$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();

This also returns in milliseconds.

Follow the scans table details:

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

Edit:

I did a test using PDO instead of mysqli and the performance improved drastically, both using bindValue() and bindParam() it returned close to the direct query speed. Although, I did not find any information showing the reason for the performance difference as mysqli has proven to be faster in Benchmarks.

I may have run into a bug that I don't understand.

To "prove" that the "bind" is at fault, pepper the PHP code with microtime(true) to separate out the call to bind.

To time any SQL query, run it twice. There are multiple caches that interfere with getting a realistic time.

  • If the data is not yet cached in the buffer_pool (or other RAM caches), the first run will be slow because of the I/O; the second will be a realistic estimate for production use of the query.

  • If the "Query cache" is ON, the second time will be on the order of 1 millisecond, regardless of how complex the query is. The QC is going away; plan for its future removal. Meanwhile, do SELECT SQL_NO_CACHE... then timing.

Back to the specific query...

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

will run faster with

INDEX(session_id, id, ts)

When Adding that, also Drop the existing INDEX(session_id) as being redundant.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM