MySQL queries within a foreach loop - performance issue? - php

The array showcasef holds 20 items per page. I do 3 different queries within the foreach loop, which is 60 queries (just for the loop, there's additional queries too).
<?php
foreach($showcasef as $itemf){
$sf_id = $itemf['sf_id'];
$sf_url = $itemf['sf_url'];
$sf_title = $itemf['sf_title'];
$sf_urltitle = post_slug($sf_title);
// Fetch number of favs
$stmt = $conn->prepare("SELECT COUNT(f_id) FROM favourites WHERE f_showcaseid=?");
$stmt->bind_param("i", $sf_id);
$stmt->execute();
$stmt->bind_result($numfFavs);
$stmt->fetch();
$stmt->close();
// Fetch class
$stmt = $conn->prepare("SELECT avg(r_class) FROM ranks WHERE r_showcaseid=?");
$stmt->bind_param("i", $sf_id);
$stmt->execute();
$stmt->bind_result($sf_class);
$stmt->fetch();
$stmt->close();
// Fetch number of classes
$stmt = $conn->prepare("SELECT COUNT(r_class) FROM ranks WHERE r_showcaseid=?");
$stmt->bind_param("i", $sf_id);
$stmt->execute();
$stmt->bind_result($numfClasses);
$stmt->fetch();
$stmt->close();
?>
Render HTML here
<?php } ?>
Will this be a severe performance issue, or are these particular queries relatively simple? If I keep the columns indexed, should it perform okay with millions of rows (potentially)? Or can the queries be optimized/simplified?
Here's how I get the showcasef:
$stmt = $conn->prepare("SELECT s_id,s_url,s_title FROM showcase WHERE s_userid=? ORDER BY s_date DESC LIMIT $skippingFactor, 20");
$stmt->bind_param("i", $u_id);
$stmt->execute();
$stmt->bind_result($sf_id,$sf_url,$sf_title);
while($stmt->fetch())
{
$showcasef[] = [
'sf_id' => $sf_id,
'sf_url' => $sf_url,
'sf_title' => $sf_title
];
}
$stmt->close();

A few suggestions here.
Reuse prepared statements
You are creating three prepared statements inside the loop. Why don't you create your statements only once, and then reuse them using multiple binds?
<?php
$stmt1 = $conn->prepare("SELECT COUNT(f_id) FROM favourites WHERE f_showcaseid=?");
$stmt1->bind_param("i", $sf_id);
$stmt1->bind_result($numfFavs);
$stmt2 = $conn->prepare("SELECT avg(r_class) FROM ranks WHERE r_showcaseid=?");
$stmt2->bind_param("i", $sf_id);
$stmt2->bind_result($sf_class);
$stmt3 = $conn->prepare("SELECT COUNT(r_class) FROM ranks WHERE r_showcaseid=?");
$stmt3->bind_param("i", $sf_id);
$stmt3->bind_result($numfClasses);
foreach($showcasef as $itemf) {
$sf_id = ...
$stmt1->execute();
$stmt1->fetch();
/* if the fetch succeedes then $numfFavs will contain the count */
$stmt2->execute();
...
$stmt3->execute();
..
}
$stmt1->close();
$stmt2->close();
$stmt3->close();
Use a single query to Count the rows and calculate the average
You can combine the second and third statement a single SQL query:
SELECT COUNT(r_class) AS cnt, AVG(r_class) AS average
FROM ranks
WHERE r_showcaseid=?
Use a single query instead a foreach loop
With the previous suggestions you can get better performances. But are you really sure you need a foreach loop?
If your IDs are returned by another query, instead of a foreach loop is better to use a subquery:
SELECT f_showcaseid, COUNT(f_id)
FROM favourites
WHERE f_showcaseid IN (SELECT id FROM ... WHERE ...)
GROUP BY f_showcaseid
or you can provide a list of IDs to the query:
SELECT f_showcaseid, COUNT(f_id)
FROM favourites
WHERE f_showcaseid IN (?,?,?,?,?)
GROUP BY f_showcaseid
(you can dynamically create the list of ? if the number of IDs is not fixed)

You could do this in a single query I think.
Something like the following:-
SELECT f_showcaseid, COUNT(f_id), avg(r_class), COUNT(r_class)
FROM ranks WHERE r_showcaseid IN (".implode(',', $showcasef).")
GROUP BY f_showcaseid
Of course, to use parameters you would need to do that a bit more elegantly:-
<?php
$stmt = $conn->prepare("SELECT f_showcaseid, COUNT(f_id), avg(r_class), COUNT(r_class)
FROM ranks WHERE r_showcaseid IN (".implode(',', str_split(str_repeat('?', count($showcasef)), 1)).")
GROUP BY f_showcaseid");
foreach($showcasef as $itemf)
{
$stmt->bind_param("i", $itemf['sf_id']);
}
$stmt->execute();
$stmt->bind_result($numfClasses);
$stmt->fetch();
$stmt->close();
?>

Related

Delete all rows with a specific ID from 3 different tables using PHP and MySQL

I would like to remove all rows from three different tables that matches a specific ID.
All three tables uses the same ID: chat_id.
How do I delete all rows from three different tables WHERE chat_id = 1234?
Example:
$stmt = $mysqli->prepare('DELETE FROM table1, table2, table3 WHERE chat_id = ?');
I should mention that this is inside a loop see below.
My full code:
$stmt = $mysqli->prepare('SELECT chat_id FROM chat_id WHERE chat_expire < NOW()');
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
$chatid[] = $row['chat_id'];
}
$stmt->close();
foreach($chatid as $id) { // Delete all old posts.
$stmt = $mysqli->prepare('DELETE FROM chat_id, chat_msg, chat_nick WHERE chat_id = ?');
$stmt->bind_param('s', $id);
$stmt->execute();
$stmt->close();
}
Write the same query three times by changing the table name, always in the same function.

mysqli prepared statement bind param array of ids

I have simple prepared statement, and i can't find solution to bind list of id's, so as you can see in first statement i get all ids that i need, and in next statement i need to put all those ids into IN clause, but i'm not able to do it, any suggestions how and what is best way to do it ?
$stmt = $mysqli->prepare("SELECT id FROM user WHERE groupId = ? ORDER BY id LIMIT ? OFFSET ?");
$stmt->bind_param("iii", $args['groupId'], $pageSize, $offset);
$stmt->execute();
$stmt->bind_result($id);
$userIds= array();
while ($stmt->fetch()) {
$userIds[] = $id;
}
$stmt= $mysqli->prepare("SELECT a.id as attendantId, a.firstName, a.lastName, c.id as caringId, c.startDate, c.endDate FROM attendant a LEFT JOIN caring c ON c.attendantId = a.id WHERE a.id IN (?)");
$stmt->bind_param('i', $userIds);
$stmt->bind_param('i', implode(',', $userIds));

MySQL SELECT COUNT returning NULL

I'm trying to get the number of comments on a particular item.
$stmt1 = $conn->prepare("SELECT COUNT(r_value) FROM ratings WHERE r_snippet=? AND r_value=3 OR r_value=2");
$stmt2 = $conn->prepare("SELECT COUNT(c_id) FROM comments WHERE c_snippet=?");
foreach ($snippets as $snippet){
$s_id = $snippet['s_id'];
$s_thumb = $snippet['s_thumb'];
$stmt1->bind_param("i",$s_id);
$stmt1->execute();
$stmt1->bind_result($numLikes);
$stmt1->fetch();
$stmt2->bind_param("i",$s_id);
$stmt2->execute();
$stmt2->bind_result($numComments);
$stmt2->fetch();
?>
** HTML here **
<?php
}
$stmt1->close();
$stmt2->close();
?>
$numLikes works fine, but $numComments seems to be returning NULL (from var_dump) and I'm not sure why. The SQL in phpMyAdmin works fine and returns the number of comments...
You probably want change this for your first query
... AND r_value=3 OR r_value=2
To
... AND (r_value=3 OR r_value=2)
OR THIS
... AND r_value IN (2,3)
But for the second query try something simple just for debug
$stmt2 = $conn->prepare("SELECT * FROM comments WHERE c_snippet=10");
then
$stmt2 = $conn->prepare("SELECT count(*) FROM comments WHERE c_snippet=10");

PHP, MySQL statement results in ZERO rows

hope someone can help me.
i have a very simple prepared SELECT statment in PHP:
$query_select = ("SELECT * FROM companies where user_name = ? ");
$stmt = $mysqli->prepare($query_select);
$stmt->bind_param("s", $user_name);
$stmt->execute();
$count = $stmt->num_rows;
in companies table I have several rows with the $user_name i`m trying to query. But i still get 0 rows as a result.
The strange thing is that the non PREPARED version works:
$query = 'SELECT * FROM companies WHERE user_name="'.$user_name.'"';
$result = $mysqli->query($query);
$count= $result->num_rows;
echo "Aantal: ".$count;
So my question is, does anyone know why the prepared version returns ZERO and the non prepared version returns the correct number of rows?
Add this line to your code between execute and num_rows statement.
$stmt->store_result();
You have to store it before counting it.
For mysqli prepared statements, you must take an additional step: storing the result.
Try this:
$query_select = ("SELECT * FROM companies where user_name = ? ");
$stmt = $mysqli->prepare($query_select);
$stmt->bind_param("s", $user_name);
$stmt->execute();
$stmt->store_result(); // <-- new line
$count = $stmt->num_rows;
May be you need to bind the result:
/* bind result variables */
$stmt->bind_result($district);
Full example here

PHP prepared statement loop JOIN query not working

I am trying to gather some variables from my query then output them using $stmt->bind_result() however I am not getting any rows returned in my search.
I am not sure what is going wrong here?
$tag = trim($_GET['tag']);
$stmt = $mysqli->prepare('SELECT trips.trip_id FROM trips JOIN tags ON trips.post_id = tags.post_id WHERE tag = ?');
$stmt->bind_param('s', $tag);
$stmt->execute();
$stmt->bind_result($id);
while ($stmt->fetch()) {
echo $id;
}

Categories