Timeout Error when doing Large select from loop - php

I have a simple php code below
$sql_items = "SELECT id FROM item_masterfile"; /* this query has 7000 rows */
$result_items = mysqli_query($con,$sql_items);
while ($row_items = mysqli_fetch_row($result_items)) {
$sql_qty = "SELECT qty FROM inventory WHERE id = ".$row_items[0];
/* rest of the code here */
}
}
this is working but due to a lot data my server cannot handle it and other queries took long to respond. how can I fix this? My target here is like batch select? to prevent clogged?
What I see in the process is a lot of select waiting to initiate.
How can I fix this?

try with batches using limit and offset like below
$offset = $i * 5000; // $i is run batch number .. 1, 2, 3 etc in the foreach() loop.
if ($i == 0) {
$offset = "";
}
$result_items="SELECT id FROM item_masterfile LIMIT 5000 OFFSET $offset;";

The code in your question shows that there is one_to_one or one_to_many relation between tables, so using pagination and join statement would resolve the problem.
Check below code hope to be helpful
$sql = "
SELECT im.id, i.qty
FROM item_masterfile AS im
JOIN inventory AS i ON
im.id = i.item_masterfile_id
LIMIT $offset, $limit
";
$result_items = mysqli_query($con,$sql);
you can set $offset and $limit dynamically in your code and go on ...

Instead of using the loop and providing id in there, you should collect all the ids in an array and then pass all of them to the query in one go using the IN operator.
Example: SELECT qty FROM inventory WHERE id IN (1,2,3,4,5). By doing this you can avoid loop and you code will not exit with timeout error.
OR
You can achieve the same using a subquery with your main query
Example: SELECT qty FROM inventory WHERE id IN (SELECT id FROM item_masterfile)

Try with follow step:
get result of first query and get id values like (1,2,3,4,...)..
and out side where clause execute second query with WHERE condition IN clause
Like
$sql_items = "SELECT id FROM item_masterfile"; /* this query has 7000 rows */
$result_items = mysqli_query($con,$sql_items);
while ($row_items = mysqli_fetch_row($result_items)) {
$ids[] = $row_items['id'];
}
$sql_qty = "SELECT qty FROM inventory WHERE id IN ".$ids;
/* rest of the code here */
}

Related

Update multiple rows for 1000 records in one go

I have one table based on which one I have to update 6 rows in the other table for matching ids. It is total of over 1000 records so most of the time I get timeout error with current script.
The way I do it now is, I select the range of ids between two dates from the first table, store it into an array and then run foreach loop making update in the second table where the ids are the same, so basically I run a query for every single id.
Is there anyway I could speed it up the process?
I found only a way to generate the each within the foreach loop
UPDATE product SET price = CASE
WHEN ID = $ID1 THEN $price1
WHEN ID = $ID1 THEN $price2
END
But I don't know how could I modify this to update multiple rows at the same time not just one.
My script code look like that
$sql = "SELECT * FROM `games` where (ev_tstamp >= '".$timestamp1."' and ev_tstamp <= '".$timestamp2."')";
while($row = mysqli_fetch_array($sql1)){
$one_of =[
"fix_id" =>$row['fix_id'],
"t1_res" =>$row['t1_res'],
"t2_res" =>$row['t2_res'],
"ht_res_t1" =>$row['ht_res_t1'],
"ht_res_t2" =>$row['ht_res_t2'],
"y_card_t1" =>$row['y_card_t1'],
"y_card_t2" =>$row['y_card_t2'],
"t1_corners" =>$row['t1_corners'],
"t2_corners" =>$row['t2_corners'],
"red_card_t1" =>$row['red_card_t1'],
"red_card_t2" =>$row['red_card_t2']
];
array_push($today_games,$one_of);
}
foreach($today_games as $key=>$val){
$cards_t1=$val['red_card_t1']+$val['y_card_t1'];
$cards_t2=$val['red_card_t2']+$val['y_card_t2'];
$sql = "Update sights SET t1_res='".$val['t1_res']."',
t2_res='".$val['t2_res']."', ev_tstamp='".$val['ev_tstamp']."',
ht_res_t1='".$val['ht_res_t1']."', ht_res_t2='".$val['ht_res_t2']."',
t1_corners='".$val['t1_corners']."',t2_corners='".$val['t2_corners']."',
t1_cards='".$cards_t1."',t2_cards='".$cards_t2."'
where fix_id='".$val['fix_id']."' "
}
Consider an UPDATE...JOIN query using fix_id as join column. Below runs mysqli parameterized query using timestamps. No loop needed.
$sql = "UPDATE sights s
INNER JOIN `games` g
ON s.fix_id = g.fix_id
AND g.ev_tstamp >= ? and g.ev_tstamp <= ?
SET s.t1_res. = g.t1_res,
s.t2_res. = g.t2_res,
s.ev_tstamp = g.ev_tstamp,
s.ht_res_t1 = g.ht_res_t1,
s.ht_res_t2 = g.ht_res_t2,
s.t1_corners = g.t1_corners,
s.t2_corners = g.t2_corners,
s.t1_cards = (g.red_card_t1 + g.y_card_t1),
s.t2_cards = (g.red_card_t2 + g.y_card_t2)";
$stmt = mysqli_prepare($conn, $sql);
mysqli_stmt_bind_param($stmt, 'ss', $timestamp1, $timestamp2);
mysqli_stmt_execute($stmt);

How to get specific data from table1, use it in table2

I'm trying to get specific rows in table 1 (stellingen). I want to store these rows to specify the rows im interested in for the second table (stelling). So lets say table 1 has 5 rows where stelling ID matches REGIOID = 5. These IDS from stelling ID I want to use to fetch the data from the second table. see the code to see what I tried. I'm not managing to find a way in order too make this happen.
So maybe too be clearer because people always say im not clear:
There are two tables. they both have a matching column. Im trying to tell the second table I want data but only if it matches the data of the first table. Like a branch of a tree. Then, I want to output some data that's in the second table.
I've tried something like this before:
SELECT
*
FROM
table2
LEFT JOIN
table1 ON
table1.ID = table2.table1_id
I've tried to create a while loop to get the data before(after the first if statement and the last += was for the variable $amountofstellinge):
$amountOfStellinge = 0;
while ($amountOfStellinge<5){
mysqli_data_seek($result, $amountOfStellinge);
Here is the code what it looks like now, its wrong, i've been messing with t a lot, but maybe it shows you what I'm trying to achieve better.
if($result = mysqli_query($con, "SELECT * FROM stellingen WHERE REGIOID=1;")) {
$row = mysqli_fetch_assoc($result);
$stellingid= $row["Stelling_ID"];
//checking.. and the output is obviously not what I want in my next query
printf($stellingid);
//defining the variable
$Timer=0;
$sql1="SELECT * FROM stelling WHERE stelling_iD=$stellingid ORDER BY Timer DESC;";
$records2 = mysqli_query($con, $sql1);
$recordscheck = mysqli_num_rows($records2);
//max 5 data
if ($recordscheck < 5){
while ($stelling = mysqli_fetch_assoc($records2)){
//At the end, i would like to only have the data that is most recent
$Timer = date('d F', strtotime($stelling['Timer']));
echo "<p><div style='color:#ED0887'>".$Timer.":</div><a target = '_blank' style='text-decoration:none' href='".$stelling['Source']."'>".$stelling['Title']."</a></p>";
}}
$recordscheck+=1; } // this is totally wrong
EDIT:
I've tried this, #noobjs
$Timer=0;
$sql1="SELECT
*
FROM
stelling
LEFT JOIN
stellingen
ON
stelling.ID = stellingen.stelling_id
WHERE
stellingen.REGIOID=1
ORDER BY stelling.Timer LIMIT 5 DESC ;";
$records2 = mysqli_query($con, $sql1);
printf($records2);
while ($stelling = mysqli_fetch_assoc($records2)){
$Timer = date('d F', strtotime($stelling['Timer']));
echo "<p><div style='color:#ED0887'>".$Timer.":</div><a target = '_blank' style='text-decoration:none' href='".$stelling['Source']."'>".$stelling['Title']."</a></p>";
}
with this error:
Warning: mysqli_fetch_assoc() expects parameter 1 to be mysqli_result, boolean given in
EDIT for more clarification
Here is some sample data
The expected results is:
every page has uses data from a different REGIOID. I expect the page to show data from the table stelling(Table 1). Accordingly to the REGIOID (Table2)
if i understand right:
SELECT
*
FROM
stelling
LEFT JOIN
stellingen
ON
stelling.stellingID = stellingen.stelling_id
WHERE
stellingen.REGIOID=1
ORDER BY stelling.Timer DESC LIMIT 5 ;

Is there a better way to run multiple SQL queries to the same table using PHP?

I have a query that requests an ID (the PK) and an order number and throws them into an array. I then loop through the returned data in the array and run two more queries to find the number of times the order number shows up in the database and to get the invoice numbers that belong to that order number. The problem I'm seeing with this setup is that it is taking a while (around 9 seconds) to return the compiled data array. Is there a faster way to get the returned results I'm looking for?
I've tried to find some articles online and came across mysqli_multi_query. Is this the better route to make multiple queries to gather the type of data I am trying to get?
<?php
require 'config.php';
$sql = "SELECT id,internal_order_number FROM orders GROUP BY internal_order_number ORDER BY created_date desc LIMIT 0 ,50";
$query=mysqli_query($mysqli, $sql);
if (!$query) {
throw new Exception(mysqli_error($mysqli)."[ $sql]");
}
$data = array();
while( $row=mysqli_fetch_array($query) ) { // preparing an array
$nestedData=array();
$nestedData['line_id'] = $row["id"];
$nestedData['internal_order_number'] = $row["internal_order_number"];
$data[] = $nestedData;
}
$compiled_data = array();
// Loop through data array with additional queries
foreach($data as $line){
$new_data = array();
// Get item counts
$item_counts = array();
$get_count = " SELECT internal_order_number FROM orders WHERE internal_order_number = '".$line['internal_order_number']."' ";
$count_query=mysqli_query($mysqli, $get_count);
while ($counts=mysqli_fetch_array($count_query)){
if (isset($item_counts[$counts['internal_order_number']])) {
$item_counts[$counts['internal_order_number']]++;
} else {
$item_counts[$counts['internal_order_number']] = 1;
}
}
$product_count = $item_counts[$line['internal_order_number']];
// Get invoice numbers
$invoice_array = array();
$get_invoices = " SELECT invoice_number FROM orders WHERE internal_order_number = '".$line['internal_order_number']."'";
$invoice_query=mysqli_query($mysqli, $get_invoices);
while ($invoice=mysqli_fetch_array($invoice_query)){
if(!in_array($invoice['invoice_number'], $invoice_array)){
$invoice_array[] = $invoice['invoice_number'];
}
}
$invoices = implode(", ",$invoice_array);
$new_data['order_number'] = $line['internal_order_number'];
$new_data['count'] = $product_count;
$new_data['invoices'] = $invoices;
$compiled_data[] = $new_data;
}
mysqli_close($mysqli);
print_r($compiled_data);
?>
What, why are you doing basically the same query 3 times. You first one selects them all, you second query requires the same table making sure the first tables order number == the tables order number and the last just grabs the invoice number...?
Just do one query:
SELECT internal_order_number, invoice_number FROM table WHERE ...
Then loop through it and do what you need. You don't need 3 queries...

Phalcon - get result of count in PHQL

I need to get number of rows from table as string.
I execute this code:
$phql = "SELECT COUNT(*) FROM Model WHERE id = $this->id";
$count = $this->getModelsManager()->createQuery($phql)->execute();
Now $count is Phalcon\Mvc\Model\Resultset\Complex object. To get a proper result I need to do something like that:
$count[0]->{0}
In my opinion this is awful. Is there any other way to get this result?
Few solutions:
1) Use simple queries:
$count = $this->db->fetchOne('SELECT COUNT(*) AS total FROM products');
2) Model aggregations
$count = Products::count(
"area = 'Testing'"
);
More info and methods: https://docs.phalconphp.com/ar/3.2/db-models in section Generating Calculations
3) If you insist of using executeQuery() you should add getFirst() in order to get only one result. Similar to PDO's fetchOne().
$phql = "SELECT COUNT(*) AS total FROM Models\Products";
$count = $this->modelsManager->executeQuery($phql)->getFirst();

PHP PDO pagination foreach

I'm trying to create a pagination for my PDO query. I cant figure it out. I've tried numerous google searches, but nothing that will work for me. [I probably didn't search hard enough. I'm not sure]
This is my code:
$sql2 = "SELECT * FROM comments WHERE shown = '1'ORDER BY ID DESC";
$stm2 = $dbh->prepare($sql2);
$stm2->execute();
$nodes2= $stm2->fetchAll();
foreach ($nodes2 as $n1) {
echo "text";
}
I want to be able to limit 10 comments per page, and use $_GET['PAGE'] for the page.
Something that I tried
$sql2 = "SELECT * FROM comments WHERE shown = '1'ORDER BY ID DESC";
$stm2 = $dbh->prepare($sql2);
$stm2->execute();
$nodes2= $stm2->fetchAll();
$page_of_pagination = 1;
$chunked = array_chunk($nodes2->get_items(), 10);
foreach ($chunked[$page_of_pagination] as $n1) {
echo "text";
}
If someone could help out, I appreciate it.
You need to limit the query that you are performing, getting all values from the database and then limiting the result to what you want is a bad design choice because it's highly inefficient.
You need to do this:
$page = (int)$_GET['PAGE']; // to prevent injection attacks or other issues
$rowsPerPage = 10;
$startLimit = ($page - 1) * $rowsPerPage; // -1 because you need to start from 0
$sql2 = "SELECT * FROM comments WHERE shown = '1' ORDER BY ID DESC LIMIT {$startLimit}, {$rowsPerPage}";
What LIMIT does:
The LIMIT clause can be used to constrain the number of rows returned by the SELECT statement. LIMIT takes one or two numeric arguments, which must both be nonnegative integer constants
More information here: http://dev.mysql.com/doc/refman/5.7/en/select.html
Then you can proceed getting the result and showing it.
Edit after comment:
To get all the pages for display you need to know how many pages are there so you need to do a count on that SELECT statement using the same filters, meaning:
SELECT COUNT(*) as count FROM comments WHERE shown = '1'
Store this count in a variable. To get the number of pages you divide the count by the number of rows per page you want to display and round up:
$totalNumberOfPages = ceil($count / $rowsPerPage);
and to display them:
foreach(range(1, $totalNumberOfPages) as $pageNumber) {
echo '' . $pageNumber . '';
}

Categories