Reputation: 1007
My SQL query updates all the stocks in database, but it is not working very efficiently and sometimes I get 504 timeout errors. The code works fine. How can I make it work better.
P.S: Please ignore lack of prepared statements, I'll add them later.
Some information about tables (Wordpress Woocommerce Plugin default tables):
wp_posts: This table includes posts. (Posts can be a product, or product variation. Example a product is butterfly t-shirt, a product variation is butterfly t-shirt red large).
wp_postmeta: This table includes meta information about posts. For example, if a product variation is instock, or what color it is, or what size it is.
//This array gives, which products are there, and their respective categories.
$allProducts = array("Fermuarlı Kapşonlu Sweatshirt" => "'2653','2659'","Kapşonlu Sweatshirt" => "'2646','2651'","Sweatshirt" => "'2644','2650'","Kadın Tişört" => "'2654','2656'","Atlet" => "'2655','2657'","Tişört" => "'2643','2304'");
//Below arrays gives information about, which product variations are out of stock.
$tisort_OutOfStock =array();
$atlet_OutOfStock =array("all_colors"=>"'3xl','4xl','5xl'");
$kadin_tisort_OutOfStock =array("all_colors"=>"'xxl','3xl','4xl','5xl'");
$sweatshirt_OutOfStock =array("beyaz"=>"'xxl','3xl','4xl','5xl'","kirmizi"=>"'xxl','3xl','4xl','5xl'","bordo"=>"'5xl'","antrasit"=>"'5xl'");
$kapsonlu_sweatshirt_OutOfStock =array("gri-kircilli"=>"'5xl'");
$fermuarli_kapsonlu_sweatshirt_OutOfStock =array("gri-kircilli"=>"'5xl'","siyah"=>"'5xl'");
//Reset stocks before updating.
$resetStocks = "UPDATE wp_postmeta set meta_value = 'instock' where meta_key = '_stock_status'";
$wpdb->query($resetStocks);
echo "Stoklar are reseted<br>";
//Foreach product, foreach color, update if product doesn't have stock.
foreach( $allProducts as $key => $urun ){
switch ($key) {
case "Kadın Tişört": $tempArray = $kadin_tisort_OutOfStock; break;
case "Fermuarlı Kapşonlu Sweatshirt": $tempArray = $fermuarli_kapsonlu_sweatshirt_OutOfStock; break;
case "Kapşonlu Sweatshirt": $tempArray = $kapsonlu_sweatshirt_OutOfStock; break;
case "Sweatshirt": $tempArray = $sweatshirt_OutOfStock; break;
case "Atlet": $tempArray = $atlet_OutOfStock; break;
case "Tişört": $tempArray = $tisort_OutOfStock; break;
}
foreach( $tempArray as $color => $size ){
$query = "UPDATE wp_postmeta set meta_value = 'outofstock' where meta_key = '_stock_status' and post_id in
(
select post_id from (select * from wp_postmeta) AS X where meta_key = 'attribute_pa_beden' and meta_value in (".$size.")
and post_id in (select post_id from (select * from wp_postmeta) AS Y where meta_key = 'attribute_pa_renk' and ((meta_value = '".$color."') OR ('".$color."' = 'all_colors')))
and post_id in (select id from wp_posts where post_type = 'product_variation' and post_parent in (select object_id FROM wp_term_relationships where term_taxonomy_id in (".$urun.")))
)";
global $wpdb;
$updatedRowCount = $wpdb->query($query);
}
}
Upvotes: 0
Views: 221
Reputation: 142560
Start by working on the key SELECT
:
SELECT post_id
from
(
SELECT *
from wp_postmeta
) AS X
where meta_key = 'attribute_pa_beden'
and meta_value in (".$size.")
and post_id in (
SELECT post_id
from
(
SELECT *
from wp_postmeta
) AS Y
where meta_key = 'attribute_pa_renk'
and ((meta_value = '".$color."')
OR ('".$color."' = 'all_colors'))
)
and post_id in (
SELECT id
from wp_posts
where post_type = 'product_variation'
and post_parent in (
SELECT object_id
FROM wp_term_relationships
where term_taxonomy_id in (".$urun.")))
)";
Yeah, I realize you need to "hide" wp_postmeta
from the UPDATE wp_postmeta
, but we can rearrange things to make it more efficient. Note how you have two cases of fetching the entire wp_postmeta
before filtering? This makes it impossible to use any indexes, hence is sloooow.
SELECT m1.post_id
FROM wp_postmeta AS m1
JOIN wp_postmeta AS m2 USING(post_id)
JOIN wp_posts AS p2 USING(post_id)
JOIN wp_term_relationships AS tr ON p2.post_parent = tr.object_id
WHERE m1.meta_key = 'attribute_pa_beden' AND m1.meta_value in ("$size")
AND m2.meta_key = 'attribute_pa_renk' AND ( m1.meta_value = '$color'
OR '$color' = 'all_colors' )
AND p2.post_type = 'product_variation'
AND tr.term_taxonomy_id IN ($urun)
Forget about the UPDATE
until you get this SELECT
debugged. (I may have made some mistakes, but doesn't it look a lot simpler? It will run a lot faster, especially with the indexes I recommend.)
The OR
with color will probably be optimized out, so I won't worry about that.
I can't predict which of the 4 tables the Optimizer will start with, so these indexes are needed to give it choices:
tr: (term_taxonomy_id, object_id) -- in this order
posts: (post_type, post_id) -- in this order
postmeta: (meta_key, meta_value) -- see note below
After Optimizer picks which table to start with, then it will go to each of the other tables in turn; the order does not matter to us. These additional indexes may be useful:
posts: (post_parent, post_id) -- in this order
postmeta: (post_id, meta_key, meta_value) -- see note below
If meta_value
is LONGTEXT
, then it cannot be in an index, so leave it out. (No, don't bother with a "prefix" index.)
If you are using MySQL 5.5 or 5.6, meta_key
is too long to be indexes; see my link for multiple workarounds.
EAV schema sucks, and you are finding out why.
Back to the kludge for UPDATE
, add the wrapper:
UPDATE wp_postmeta AS m
JOIN ( SELECT post_id
FROM ( the above query )
) AS kludge USING (post_id)
SET m.meta_value = 'outofstock'
WHERE m.meta_key = '_stock_status'
Upvotes: 2
Reputation: 142560
SELECT post_id
from
(
SELECT *
from wp_postmeta
) AS X
where ...
-->
SELECT post_id
FROM wp_postmeta
WHERE ...
(The subquery only slows down things.)
and post_id in (
SELECT post_id
Instead of IN ( SELECT ... )
, use a JOIN
.
In addition to those tips, see my tips on improving the postmeta schema.
Upvotes: 1