Optimise SQL Script with multiple joins on the same table - mysql

I have a search query that is slow, takes around 28 seconds to run. I want to decrease its running time to under 1 second, I am sure the reason it is slow might have to do with the way I'm Inner Joining multiple times the same table.
Any advice that can point me in the right direction is most appreciated.
Here is my query:
SELECT
wp_posts.ID,
wp_posts.post_title
FROM wp_posts
INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id )
INNER JOIN wp_postmeta AS mt1 ON ( wp_posts.ID = mt1.post_id AND ( mt1.meta_key = 'wpcm_frdate' AND mt1.meta_value IN ('2017','2018','2014') ))
INNER JOIN wp_postmeta AS mt2 ON ( wp_posts.ID = mt2.post_id AND ( mt2.meta_key = 'vehicle_type' AND mt2.meta_value IN ('HATCHBACK','SEDAN') ) )
INNER JOIN wp_postmeta AS mt3 ON ( wp_posts.ID = mt3.post_id AND ( mt3.meta_key = 'vehicle_transmission' AND mt3.meta_value IN ('AUTOMATIC','MANUAL','DSG') ) )
INNER JOIN wp_postmeta AS mt4 ON ( wp_posts.ID = mt4.post_id AND ( mt4.meta_key = 'symbol' AND mt4.meta_value IN ('!','%','*') ) )
INNER JOIN wp_postmeta AS mt5 ON ( wp_posts.ID = mt5.post_id AND ( mt5.meta_key = 'stock_code' AND mt5.meta_value IN ('2020','3380','4563','12063') ))
INNER JOIN wp_postmeta AS mt6 ON ( wp_posts.ID = mt6.post_id AND ( mt6.meta_key = 'wpcm_mileage' AND CAST(mt6.meta_value AS SIGNED) BETWEEN '0' AND '305000' ))
INNER JOIN wp_postmeta AS mt7 ON ( wp_posts.ID = mt7.post_id AND ( mt7.meta_key = 'wpcm_price' AND CAST(mt7.meta_value AS SIGNED) BETWEEN '0' AND '1500000' )
AND ( wp_postmeta.meta_key = 'wpcm_make' AND wp_postmeta.meta_value IN ('68','74') ))
INNER JOIN wp_postmeta AS mt8 ON ( wp_posts.ID = mt8.post_id AND ( mt8.meta_key = 'wpcm_model' AND mt8.meta_value IN ('84','75','151','69','91','223','247','70') ) )
INNER JOIN wp_postmeta AS mt9 ON ( wp_posts.ID = mt9.post_id AND ( ( mt9.meta_key = 'wpcm_condition' AND mt9.meta_value IN ('new','pre-owned','top-marques') )))
WHERE 1=1 AND wp_posts.post_type = 'wpcm_vehicle' AND ((wp_posts.post_status = 'publish'))
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_date DESC;

Related

Need help optimizing query that is taking >28 seconds and eating cpu

I have a wordpress installation with a large amount of entries (posts) in the table.
I have the following query that is taking almost 30 seconds. Any ideas on how I can optimize?
I think that the cast is what is stalling here but not sure.
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
FROM wp_posts
INNER JOIN wp_postmeta
ON ( wp_posts.ID = wp_postmeta.post_id )
INNER JOIN wp_postmeta AS mt1
ON ( wp_posts.ID = mt1.post_id )
WHERE 1=1
AND ( wp_postmeta.meta_key = 'post_views_count_7_day_total'
AND ( mt1.meta_key = 'post_views_count_7_day_last_date'
AND CAST(mt1.meta_value AS SIGNED) > '1626290358' ) )
AND wp_posts.post_type = 'post'
AND ((wp_posts.post_status = 'publish'))
GROUP BY wp_posts.ID
ORDER BY CAST(wp_postmeta.meta_value AS SIGNED) DESC
LIMIT 0, 3

SQL - Select a variable that needs to be populated

Long time no see !
I'm using wordpress for my site with lots of custom post_type and multiple category system with toxonomies set by the Toolset plugin.
I'm trying to store some posts into a mysql table from a huge query that i want to cron each night to increase speed of my site.
Here is what I did :
SELECT wp_posts.ID as mid,wp_posts.post_title,wp_posts.post_name,(
SELECT COUNT(wp_posts.ID) FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) INNER JOIN wp_postmeta AS mt1 ON ( wp_posts.ID = mt1.post_id ) LEFT JOIN wp_icl_translations t
ON wp_posts.ID = t.element_id
AND t.element_type = CONCAT('post_', wp_posts.post_type) WHERE 1=1 AND (
( wp_postmeta.meta_key = 'my_key' AND wp_postmeta.meta_value = mid )
AND
(
( mt1.meta_key = 'end_date' AND CAST(mt1.meta_value AS SIGNED) >= date_format(curdate(), '%Y%m%d') )
OR
( mt1.meta_key = 'end_date' AND CAST(mt1.meta_value AS SIGNED) = '' )
)
) AND wp_posts.post_type IN ('bp','code') AND ((wp_posts.post_status = 'publish'))
) AS countpost
FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1 AND ( ( wp_postmeta.meta_key = 'top-key' AND wp_postmeta.meta_value = 'yes' ) ) AND wp_posts.post_type = 'my_type' AND ((wp_posts.post_status = 'publish')) GROUP BY wp_posts.ID ORDER BY wp_posts.post_title
It work great but i want to add a column !
The columni want should look like an "array" of "term_taxonomy_id" of the "COUNT(wp_posts.ID) query result" like this :
SELECT group_concat(term_taxonomy_id) FROM `bpo_term_relationships` WHERE `object_id` = id_of_the_current_post_scanned_by_count_query
my result should look like this
bpo_posts.ID | bpo_posts.post_title | bpo_posts.post_name | COUNT(bpo_posts.ID) | "array" of "term_taxonomy_id"
1 | the title | the-title | 16 | 815,712,1025
2 | hey you | hey-you | 5 | 75,105,200
...
...
I'm stuck :(
Anybody has an idea ?
Thanks.
I finally achieve what I wanted to do !
Here is the code :
ALTER EVENT wp_mytable
ON SCHEDULE EVERY 1 DAY
STARTS '2016-12-02 01:00:00'
DO
INSERT INTO wp_mytable (mid, name, title, cats, posts)
SELECT wp_posts.ID as mid, #titlex := wp_posts.post_title, #namex := wp_posts.post_name,(
SELECT group_concat(DISTINCT term_taxonomy_id) FROM `wp_term_relationships` WHERE `object_id` IN (
SELECT wp_posts.ID as idx FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) INNER JOIN wp_postmeta AS mt1 ON ( wp_posts.ID = mt1.post_id ) LEFT JOIN wp_icl_translations t
ON wp_posts.ID = t.element_id
AND t.element_type = CONCAT('post_', wp_posts.post_type) WHERE 1=1 AND (
( wp_postmeta.meta_key = 'my-key' AND wp_postmeta.meta_value = mid )
AND
(
( mt1.meta_key = 'end_date' AND CAST(mt1.meta_value AS SIGNED) >= date_format(curdate(), '%Y%m%d') )
OR
( mt1.meta_key = 'end_date' AND CAST(mt1.meta_value AS SIGNED) = '' )
)
) AND wp_posts.post_type IN ('bp','code') AND ((wp_posts.post_status = 'publish'))
)
) as cats,#countpostx := (
SELECT COUNT(wp_posts.ID) FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) INNER JOIN wp_postmeta AS mt1 ON ( wp_posts.ID = mt1.post_id ) LEFT JOIN wp_icl_translations t
ON wp_posts.ID = t.element_id
AND t.element_type = CONCAT('post_', wp_posts.post_type) WHERE 1=1 AND (
( wp_postmeta.meta_key = 'my-key' AND wp_postmeta.meta_value = mid )
AND
(
( mt1.meta_key = 'end_date' AND CAST(mt1.meta_value AS SIGNED) >= date_format(curdate(), '%Y%m%d') )
OR
( mt1.meta_key = 'end_date' AND CAST(mt1.meta_value AS SIGNED) = '' )
)
) AND wp_posts.post_type IN ('bp','code') AND ((wp_posts.post_status = 'publish'))
) AS countpost
FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1 AND ( ( wp_postmeta.meta_key = 'top-key' AND wp_postmeta.meta_value = 'yes' ) ) AND wp_posts.post_type = 'my_type' AND ((wp_posts.post_status = 'publish')) GROUP BY wp_posts.ID ORDER BY wp_posts.post_title
ON DUPLICATE KEY
UPDATE `name`=#namex, `title`=#titlex, `posts`=#countpostx, `cats`=cats
Not sure this could be better but it works :)
Ask if you need some explanation :)

Getting issue in union of 2 queries

I am getting an issue in below query -
SELECT DISTINCT id
FROM wp_posts
INNER JOIN wp_postcodes ON (
wp_postcodes.post_id = wp_posts.id
AND wp_posts.post_type = 'listing'
AND TRUNCATE (
(degrees(acos(sin(radians(latitude)) * sin(radians('37.090240')) + cos(radians(latitude)) * cos(radians('37.090240')) * cos(radians(longitude - '-95.712891')))) * 69.09),
1
) <= 400
AND TRUNCATE (
(degrees(acos(sin(radians(latitude)) * sin(radians('37.090240')) + cos(radians(latitude)) * cos(radians('37.090240')) * cos(radians(longitude - '-95.712891')))) * 69.09),
1
) >= 40
)
INNER JOIN wp_postmeta ON (
wp_postmeta.post_id = wp_posts.id
AND wp_posts.post_type = 'listing'
AND wp_posts.post_status = 'publish'
AND (
(
meta_key = 'city'
AND meta_value = 'sports'
)
OR (
meta_key = 'state'
AND meta_value = 'sports'
)
OR post_title = 'sports'
)
)
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
LEFT JOIN wp_terms ON (wp_terms.term_id = wp_term_relationships.term_taxonomy_id)
INNER JOIN wp_term_taxonomy ON (
wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id
AND wp_term_taxonomy.taxonomy = 'listingcategory'
AND wp_term_taxonomy.term_id = 406
)
UNION
DISTINCT
SELECT DISTINCT id
FROM wp_posts
INNER JOIN wp_postcodes ON (
wp_postcodes.post_id = wp_posts.id
AND wp_posts.post_type = 'listing'
AND TRUNCATE (
(degrees(acos(sin(radians(latitude)) * sin(radians('37.090240')) + cos(radians(latitude)) * cos(radians('37.090240')) * cos(radians(longitude - '-95.712891')))) * 69.09),
1
) <= 400
AND TRUNCATE (
(degrees(acos(sin(radians(latitude)) * sin(radians('37.090240')) + cos(radians(latitude)) * cos(radians('37.090240')) * cos(radians(longitude - '-95.712891')))) * 69.09),
1
) >= 40
)
INNER JOIN wp_postmeta ON (
wp_postmeta.post_id = wp_posts.id
AND wp_posts.post_type = 'listing'
AND wp_posts.post_status = 'publish'
AND (
(
meta_key = 'city'
AND meta_value LIKE '%sports%'
)
OR (
meta_key = 'state'
AND meta_value LIKE '%sports%'
)
OR post_title LIKE '%sports%'
)
)
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
LEFT JOIN wp_terms ON (wp_terms.term_id = wp_term_relationships.term_taxonomy_id)
INNER JOIN wp_term_taxonomy ON (
wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id
AND wp_term_taxonomy.taxonomy = 'listingcategory'
AND wp_term_taxonomy.term_id = 406
)
here it have 2 queries with union, 1st getting no output but 2nd getting output. And I am performing union of both queries. here should be a result
but I am getting no result. Please suggest what mistake I am doing..
UNION operation try to merge the result sets and remove the duplicates. Try UNION ALL and see
Thanks for reply.
I have resolved my issue, here UNION is working fine for me instead of UNION DISTINCT. Now my concern has been solved.

Ordering results of MySQL query (using join)

In a WordPress installation, I need to order products so that:
Sold products show up last.
Sold products tagged "antique" show up after sold products tagged "reproduction."
I have successfully completed the first item, but I am at a loss regarding the second item. I'm not getting any errors. My problem is that everything in my ORDER BY statement is working except for "wt.slug DESC." If I change the LEFT JOIN statements for wp_term_taxonomy and wp_terms tables to INNER JOIN statements, I get 0 results, so it looks to me like these statements are not finding the results that I expect. Here is my query:
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
FROM wp_posts
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id )
LEFT JOIN wp_postmeta stock ON ( wp_posts.ID = stock.post_id AND stock.meta_key = '_stock_status' )
LEFT JOIN wp_term_taxonomy wtt ON ( wp_term_relationships.term_taxonomy_id = wtt.term_taxonomy_id AND wtt.taxonomy = 'product_tag' )
LEFT JOIN wp_terms wt ON ( wtt.term_id = wt.term_id AND ( wt.slug = 'antique' OR wt.slug = 'reproduction' ) )
WHERE 1=1
AND ( wp_term_relationships.term_taxonomy_id IN (171) )
AND ( ( wp_postmeta.meta_key = '_visibility' AND CAST(wp_postmeta.meta_value AS CHAR) IN ('visible','catalog') ) )
AND wp_posts.post_type = 'product'
AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private')
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_type DESC, stock.meta_value ASC, wt.slug DESC, wp_posts.post_date
Here is the WordPress database description for reference. I would appreciate any assistance.
You can create a new field as
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID, CASE wt.slug WHEN 'antique' THEN -1 WHEN 'reproduction' THEN 0 ELSE 1 END as sort_order
and use the sort_order in ORDER BY clause like
ORDER BY sort_order DESC
Thanks to help from #mynawaz, I have been able to come up with a solution. I'm not sure if it's the most efficient or elegant solution, but it works:
SELECT SQL_CALC_FOUND_ROWS wp_posts.* , CASE wt.slug WHEN 'antique' THEN 1 WHEN 'reproduction' THEN 2 ELSE 0 END as slug_order
FROM wp_posts
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id )
LEFT JOIN wp_postmeta stock ON ( wp_posts.ID = stock.post_id AND stock.meta_key = '_stock_status' )
LEFT JOIN wp_term_relationships wtr ON ( wp_posts.ID = wtr.object_id AND stock.meta_value = 'outofstock' )
LEFT JOIN wp_term_taxonomy wtt ON ( wtr.term_taxonomy_id = wtt.term_taxonomy_id AND wtt.taxonomy = 'product_tag' )
LEFT JOIN wp_terms wt ON ( wtt.term_id = wt.term_id AND wt.slug IN( 'antique','reproduction' ) )
WHERE 1=1
AND ( wp_term_relationships.term_taxonomy_id IN (171) )
AND ( ( wp_postmeta.meta_key = '_visibility' AND CAST(wp_postmeta.meta_value AS CHAR) IN ('visible','catalog') ) )
AND wp_posts.post_type = 'product'
AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private')
AND NOT (
stock.meta_value = 'outofstock'
AND ( CASE wt.slug WHEN 'antique' THEN 1 WHEN 'reproduction' THEN 2 ELSE 0 END ) = 0
)
GROUP BY wp_posts.ID, slug_order
ORDER BY wp_posts.post_type DESC, stock.meta_value ASC, slug_order DESC, wp_posts.post_date DESC

How to get result count from mysql inner join

I have a mysql query something like this.
SELECT SQL_CALC_FOUND_ROWS wp_posts . * , wp_geodir_gd_place_detail . *
FROM wp_posts
INNER JOIN wp_geodir_gd_place_detail ON ( wp_geodir_gd_place_detail.post_id = wp_posts.ID )
INNER JOIN wp_term_relationships ON ( wp_posts.ID = wp_term_relationships.object_id )
WHERE 1 =1
AND (
wp_posts.post_status = 'publish'
OR wp_posts.post_status = 'private'
)
AND wp_posts.post_type = 'gd_place'
AND (
wp_term_relationships.term_taxonomy_id
IN ( 2, 6, 8 )
)
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_title ASC , wp_posts.post_title ASC
But its returning full rows with details. Can someone help me to get the count of affected rows instead of full rows?