Problems with slow queries - php

Problem
I have a magento store, this store run an script that sync intranet products and store, this script run each 1 hour, my server administrator block the site access because this script is getting slow queries.
Question
My script just read a CSV file and for each row check if the SKU already registered, if already update weight, stock and price, have a better way to do this?
this is my script.
$produto = Mage::getModel('catalog/product');
$productId = $produto->getIdBySku($sku);
$produto->load($productId);
if ($produto->getId()) {
$stock = $produto->getStockData();
$stock['qty'] = $quantidade;
$stock['is_in_stock'] = $this->initStock($quantidade);
$stock['manage_stock'] = 1;
$stock['use_config_manage_stock'] = 1;
$produto->setData('price', $preco);
if ($altura > 0)
$produto->setData('volume_altura', $altura);
if ($comprimento > 0)
$produto->setData('volume_comprimento', $comprimento);
if ($largura > 0)
$produto->setData('volume_largura', $largura);
$produto->setData('weight', $this->initWeight($peso));
$produto->setStockData($stock);
$produto->save();
} else {
$produto = Mage::getModel('catalog/product');
$produto->setTypeId('simple');
$produto->setAttributeSetId(4);
$produto->setData('tax_class_id', 0);
$produto->setVisibility(1);
$produto->setStatus(1);
$produto->setData('sku', $sku);
$produto->setData('color', $cor);
$produto->setData('name', utf8_encode($descricao));
$produto->setData('marca', $this->initAttribute(148, $marca));
$produto->setData('codigo_barra', $codBarra);
$produto->setData('price', $preco);
if ($altura > 0)
$produto->setData('volume_altura', $altura);
if ($comprimento > 0)
$produto->setData('volume_comprimento', $comprimento);
if ($largura > 0)
$produto->setData('volume_largura', $largura);
$produto->setData('cost', $custo);
$stock['qty'] = $quantidade;
$stock['is_in_stock'] = $this->initStock($quantidade);
$stock['manage_stock'] = 1;
$stock['use_config_manage_stock'] = 1;
$produto->setStockData($stock);
$produto->setData('weight', $this->initWeight($peso));
$produto->save();
}

Is there any way to reduce the number of items in the CSV file? I mean, if you send all items every time and for each one of them you make a query, the number of queries you make and the time that will take the script to finish will be too high.
I recommend you to only sync with the store the new items or the items with updates values, it will decrease the number of rows in the CSV and the number of queries too, also, if you include in your CSV file a field with a flag Updated/New or something like this, you can avoid the first query to check if the product exists in the case of the "New" flag is found.
I hope it helps.

Related

Programmatic cost for each purchase

I'm currently trying to identify which purchase is costing our company more than 40. Each purchase is an array of data I get through an API, and the cost is pulled from a mysql database. I have been trying with a while and a for each loop but after multiple attempt I think using one loop will be the best for performance and accuracy.
$result is the MYSQL data, and $json_array contains the API data. I would like to join the 2 data sets within a loop so I can identify the purchase_id for any purchase that costing us more than 40.
Any help much appreciated!
I have already tried 2 different loops but it won't work. It needs to be in one loop instead of 2.
//Getting the MySQL Results
$result=mysqli_query($conn,$sql);
//Creating empty array
$overspend = array();
//Starting the loop
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
//If the cost if more than 40 continue
if($row["cost"] > 40){
array_push($overspend, $row['purchase_id'] );
if (in_array($json_array, $overspend)){
$count = array_count_values($json_array);
${'_'.$row['purchase_id'].'_l'} = $count[$row['purchase_id']];
${'_'.$row['purchase_id']} = $row['cost'];
if((${'_'.$row['purchase_id']}/${'_'.$row['purchase_id'].'_l'}) > 40){
echo ${'_'.$row['purchase_id']};
}
}
}
}
}
I am not getting any error messages, I am just not getting the result expected. The expected result should be the keyword id.

Stopping a PHP loop when updating MySQL database

I'm creating a basic main menu for a stock market simulator where the price of a company will be updated periodically. For testing purposes, I need to make a loop to display the price of a share on the website five times (with the website automatically updating without refreshing) and to update the database at the same time.
I have successfully wrote some code which will both update the database with the current share price and will also update the website as well. However, when I have tried to include a loop I have come to a problem. I have included a loop to iterate five times but the problem that I am having is that the code continues to iterate even after five tries.
PHP:
<?php
$conn = mysqli_connect("localhost", "root", "", "prices");
if ($conn->connect_error)
{
die("Connection error: ". $conn->connect_error);
}
$result = $conn->query("SELECT `price` FROM `priceTable` WHERE `company` = 'Bawden'");
$x = 0;
if ($result->num_rows > 0)
{
while ($row = $result->fetch_assoc())
{
echo $row['price'];
echo '<br><br>';
echo $x;
if ($x < 5)
{
$random = (rand(3300, 3700) / 100);
$sql = $conn->query("UPDATE `priceTABLE` SET `price` = '$random' WHERE `company` = 'Bawden'");
$x++;
}
}
}
?>
The above code will be displayed in a separate document with Javascript code and I can post this if required in the original post however I originally chose not to as I believe this is a PHP only problem. I have chosen to display $x to see if the value will increment. However, when running, the value of $x will stay at 0.
My expected result is that, on the website, there will only be five different updates and in the database, the database will only be updated five times.
However, my actual result is that the website and database are both continuously being updated, not stopping after five times.
I'm trying to limit the update command to only 5 updates yes. At the
moment, for testing purposes, there is only one company in my database
with one price only. So I'm updating this one company's price five
times
If you need to do the update 5 times for each row returned from the database, change your if statement to a for loop. Change this :-
if ($x < 5)
{
$random = (rand(3300, 3700) / 100);
$sql = $conn->query("UPDATE `priceTABLE` SET `price` = '$random' WHERE `company` = 'Bawden'");
$x++;
}
to this
for ($x = 0, $x < 5, $x++)
{
$random = (rand(3300, 3700) / 100);
$sql = $conn->query("UPDATE `priceTABLE` SET `price` = '$random' WHERE `company` = 'Bawden'");
}
This will repeat the process exactly 5 times and not rely on a separate counter (remove the other references to $x). Not sure why you would want to update the same record 5 times with different random values though.
The else will break the first loop, the second one will stop on the first while loop.
while ($row = $result->fetch_assoc())
{
echo $row['price'];
echo '<br><br>';
echo $x;
if ($x < 5)
{
$random = (rand(3300, 3700) / 100);
$sql = $conn->query("UPDATE `priceTABLE` SET `price` = '$random' WHERE `company` = 'Bawden'");
$x++;
}else{
break;
}
break;
}
What makes you think the loop should stop after 5 iterations?
You need to add the condition $x<5 in the while ($row = $result->fetch_assoc())
Edit following your comment
What you initially wrote is something like loop hundreds of times if need be and do something in the first 5 occurrences (starting loop 6, keep looping but do nothing).
Now for the 2nd half of your comment, I'm not sure what you mean.
What I see in your code is:
Select all prices for company = 'Bawden'
Update all the prices for company = 'Bawden' 5 times (loop) with a random value, the same one, on all the records.
Not enough information to tell for sure but I don't think it makes sense: on one hand, you except to have several records under company = 'Bawden (= reason why you created a loop), on the other hand, your update feels like it is written under the assumption there would be 1 record only...
Are you missing something like a price date from your table? What is the primary key of priceTable?
Try to post more technical details about your table (definition, sample of data) or it will be complicated to help further.

Recursive call for cron job

I have a three PHP script, from which two are running as a separate cron job each day in server.
First script(get_products.php), make curl call to external server to get all products data and stored that data in database. Note that there are around 10000 products and increasing each day.
In Second script(find_related.php), selects products from database stored by first script, perform some operations and store operational data in another database. Each product have 10 rows so in this database there is around 100000 rows. This script is running as cron. Sometimes the script is not executed fully and that's why, the actual and expecting results are not stored in database. I included this line of code in script: ini_set('max_execution_time', '3600');
But it not works.
Here is the process done in this script:
Normally task is to find 10 related products based on tags. I have around 10300 products stored in my DB. Each time query take one product and their tags and try to randomly find one product tagged with same tag as main product and store the related product data into another DB for third script. Only one product per tag is allowed. If it will not find total of 10 related products then randomly gets products from another DB named bestseller_products.
Here is my code:
$get_all_products = mysql_query('SELECT * FROM store_products');
while($get_products_sql_res = mysql_fetch_array($get_all_products)){
$related_products = array();
$tags = explode(",",$get_products_sql_res['product_tags']);
$product_id = $get_products_sql_res['product_id'];
$product_handle = $get_products_sql_res['product_handle'];
$get_products_sql = mysql_query('SELECT * FROM related_products WHERE product_handle="'.$product_handle.'"');
if (mysql_num_rows($get_products_sql)==0)
{
$count = 0;
foreach($tags as $t){
$get_related_products_sql = mysql_query("SELECT product_handle, product_title, product_image FROM store_products WHERE product_tags like '%".$t."%' AND product_id != '".$product_id."' ORDER BY RAND()");
if(!$get_related_products_sql){
continue;
}
while($get_related_products = mysql_fetch_array($get_related_products_sql) ){
$related_product_title = mysql_real_escape_string($get_related_products['product_title']);
$found = false;
foreach($related_products as $r){
if($r['handle'] == $get_related_products['product_handle']){
$found = true;
break;
}
}
if($found == false){
$related_products[$count]['handle'] = $get_related_products['product_handle'];
mysql_query("INSERT INTO related_products (product_handle, product_id, related_product_title, related_product_image, related_product_handle) VALUES ('$product_handle','$product_id','$related_product_title', '$get_related_products[2]', '$get_related_products[0]')");
$count = $count + 1;
break;
}
}
}
if($count < 10){
$bestseller_products = mysql_query("SELECT product_handle, product_title, product_image FROM bestseller_products WHERE product_id != '".$product_id."' ORDER BY RAND() LIMIT 10");
while($bestseller_products_sql_res = mysql_fetch_array($bestseller_products)){
if($count < 10){
$found = false;
$related_product_title = mysql_real_escape_string($bestseller_products_sql_res['product_title']);
$related_product_handle = $bestseller_products_sql_res['product_handle'];
foreach($related_products as $r){
if($r['handle'] == $related_product_handle){
$found = true;
break;
}
}
if($found == false){
$related_product_image = $bestseller_products_sql_res['product_image'];
mysql_query("INSERT INTO related_products (product_handle, product_id, related_product_title, related_product_image, related_product_handle) VALUES ('$product_handle','$product_id','$related_product_title', '$related_product_image', '$related_product_handle')");
$count = $count + 1;
}
}
}
}
}
}
Third script(create_metafields.php), created metafields in external server using data created by second script. And same problem arises as in second script.
So i want to execute the second script into parts. I mean, not to process all 10000 products in one call but want to run unto parts(1-500,501-1000,1001-1500,..) like it. But dont want to create separate cron jobs. Please suggest if someone has solution. I really need to figure it out.
Thanks in advance!

PHP/MYSQL if else

I am creating a baseball website and I am learning php as I go. I have hit a snag with something I am trying to do; here is what my current code shows:
here is my code:
When I load my files that update the scores, if the game hasn't started the scores are NULL. Is there a code to change it to 0 without having to change it in my database. Any info will be helpful
In your select statement you can use the IFNULL(expr1, 0) function, but you will need to list your columns explicitly instead of using select *. So it would be roughly:
select
game_date,
game_time,
...,
IFNULL(AWAY_SCORE, 0),
IFNULL(HOME_SCORE, 0)
FROM scoreboard;
Yup, by way of PHP. It could also be done in the database query
while($row = $result->fetch_assoc(){
$ascore = $row['score'];
$hscore= $row['score'];
if($ascore == ""){
$ascore = 0;
if($hscore== ""){
$hscore = 0;
}
REST OF YOUR CODE HERE
}
}

PDO 'too many connections' when I select all rows from DB

I am trying to write a function that verifies a bank transaction amount against all purchases linked to that transaction. It is possible to link a purchase to more than one transaction and for more than one purchase to link to the same transaction.
The function works by totalling the transactions in question, then running a DB query to select all purchases, then checking each purchase to see if it references any of the transactions in question. It then totals the amount of all purchases linked to any of the transactions and reconciles it by checking if the two totals add up.
My problem is that I always get a 'too many connections' error when I get all the purchases from the database. It's fine if I limit the search, but I need all of them in order for the function to work.
I either need to fix the connection overload issue somehow write the query to only search for purchases containing those transactions - but I'm not sure how to do that.
The transactions are comma separated in a column of the purchase entry.
Interestingly, if the list of purchases is called via AJAX it works fine. But if the page (including other prior connections) is loaded statically - it doesn't work. I'm assuming that because the AJAX is loading one thing, there are no prior connections in that instance.
It is quite a complicated system so this may not be very helpful on its own:
public static function verify($ids, $return = NULL) {
// Transaction total
$transactions = explode(",",$ids);
$transTotal = 0;
foreach($transactions as $transaction) {
$transTotal = $transTotal + self::get($transaction,"amount");
}
// Expense/item total
$accounts = AccItem::getAll("all");
$itemTotal = 0;
foreach($accounts as $item) {
$translink = explode(",",$item->transaction_ids);
if(array_intersect($transactions, $translink)) {
$itemTotal = $itemTotal + AccItem::calculate($item->id,"total") + AccItem::calculate($item->id,"tax");
}
}
unset($accounts);
if($transTotal == $itemTotal or $transTotal + $itemTotal == 0) {
if($return) return 'check';
if(!$return) echo '<abbr title="Transaction verified."><i class="fa fa-check-circle"></i></abbr>';
} else {
if(!$return) echo '<abbr title="Transaction amount mismatch!"><i class="fa fa-exclamation-circle"></i></abbr>';
}
}
And here is the getAll function:
public static function getAll($chart_id, $date_from = 0, $date_to = 9999999999999) {
$db = new Data;
if($chart_id == "all") {
$sql = $db->query("SELECT * FROM mc_account_items WHERE date_incurred >= :date_from AND date_incurred <= :date_to ORDER BY date_incurred DESC");
} else {
$sql = $db->query("SELECT * FROM mc_account_items WHERE chart_id = :chart_id AND date_incurred >= :date_from AND date_incurred <= :date_to ORDER BY date_incurred DESC");
$sql->bindParam(":chart_id", $chart_id);
}
$sql->bindParam(":date_from", $date_from);
$sql->bindParam(":date_to", $date_to);
$sql->setFetchMode(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE,'AccItem');
$sql->execute();
return $sql->fetchAll();
//unset($db);
}
So I read into things a bit more, turns out I wanted a persistent connection as it was the same connection every time. Instead of opening a new one it will just use the cached connection.
PDO::ATTR_PERSISTENT => true

Categories