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 :)
Related
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
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;
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
I'm still pretty new to SQL, and I'm having trouble wrapping my mind around why one of these queries functions properly and one does not. This is stemming from my attempts to optimize a complex and slow query. #kalengi suggested what looks like a brilliant solution to me, but it doesn't seem to work on my site. Here are the queries.
This is the standard SQL that WordPress generates (this is working as expected):
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_posts.post_type = 'product'
AND (wp_posts.post_status = 'publish')
AND (
(wp_postmeta.meta_key = '_visibility' AND CAST(wp_postmeta.meta_value AS CHAR) IN ('visible','catalog'))
AND (mt1.meta_key = '_stock_status' AND CAST(mt1.meta_value AS CHAR) = 'instock')
)
GROUP BY wp_posts.ID
ORDER BY wp_posts.menu_order,wp_posts.post_title asc
LIMIT 0, 10
This is the SQL after #kalengi's filter processes it to combine the multiple INNER JOINs into one (this returns 0 results):
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
FROM wp_posts
INNER JOIN wp_postmeta AS pmta ON (wp_posts.ID = pmta.post_id)
WHERE 1=1
AND wp_posts.post_type = 'product'
AND ( wp_posts.post_status = 'publish' )
AND (
( pmta.meta_key = '_visibility' AND CAST(pmta.meta_value AS CHAR) IN ( 'visible','catalog' ) )
AND ( pmta.meta_key = '_stock_status' AND CAST(pmta.meta_value AS CHAR) = 'instock' )
)
GROUP BY wp_posts.ID
ORDER BY wp_posts.menu_order,wp_posts.post_title asc
LIMIT 0, 10
Can anyone explain whey the second one doesn't work to me?
The two inner joins:
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)
represent two data sets (that happen to be "the same").
Given the WHERE condition, the results will be sets of two rows where the first (wp_postmeta) meets one condition:
(wp_postmeta.meta_key = '_visibility' AND CAST(wp_postmeta.meta_value AS CHAR) IN ('visible','catalog'))
And the second meets a completely different condition:
(mt1.meta_key = '_stock_status' AND CAST(mt1.meta_value AS CHAR) = 'instock')
By combining everything into one INNER JOIN, you're instead looking for ONE ROW which matches both conditions. Apparently there isn't one.
If you review the "brilliant solution", you'll see that 'AND's were changed to 'OR' to preserve the semantics:
AND (
( pmta.meta_key = '_visibility' AND CAST(pmta.meta_value AS CHAR) IN ( 'visible','catalog' ) )
OR ( pmta.meta_key = '_stock_status' AND CAST(pmta.meta_value AS CHAR) = 'instock' )
)
It looks like you have a condition in your WHERE clause that is looking for two values at the same time in the pmta.meta_key and pmta.meta_value columns:
....
( pmta.meta_key = '_visibility' AND CAST(pmta.meta_value AS CHAR) IN ('visible','catalog' ) )
AND ( pmta.meta_key = '_stock_status' AND CAST(pmta.meta_value AS CHAR) = 'instock' )
....
One column cannot have two different values in the same row, so this test will return FALSE, and consequently, no rows will be returned.
If you rewrite the original query to group the join conditions into the ON clauses, you can see why your second query won't work:
SELECT
SQL_CALC_FOUND_ROWS wp_posts.ID
FROM
wp_posts
INNER JOIN wp_postmeta
ON wp_posts.ID = wp_postmeta.post_id
AND wp_postmeta.meta_key = '_visibility'
AND CAST(wp_postmeta.meta_value AS CHAR) IN ('visible','catalog')
INNER JOIN wp_postmeta AS mt1
ON wp_posts.ID = mt1.post_id
AND mt1.meta_key = '_stock_status'
AND CAST(mt1.meta_value AS CHAR) = 'instock'
WHERE
1=1
AND wp_posts.post_type = 'product'
AND wp_posts.post_status = 'publish'
GROUP BY
wp_posts.ID
ORDER BY
wp_posts.menu_order,
wp_posts.post_title asc
LIMIT 0, 10
If you want to join the table only once, try something like this:
SELECT
SQL_CALC_FOUND_ROWS wp_posts.ID
FROM
wp_posts
INNER JOIN wp_postmeta
ON wp_posts.ID = wp_postmeta.post_id
AND (
wp_postmeta.meta_key = '_visibility'
AND CAST(wp_postmeta.meta_value AS CHAR) IN ('visible','catalog')
) OR (
wp_postmeta.meta_key = '_stock_status'
AND CAST(wp_postmeta.meta_value AS CHAR) = 'instock'
)
WHERE
1=1
AND wp_posts.post_type = 'product'
AND wp_posts.post_status = 'publish'
GROUP BY
wp_posts.ID
ORDER BY
wp_posts.menu_order,
wp_posts.post_title asc
LIMIT 0, 10
I want to order by first featured_due then nard_apply_date_due and then post_date
$join .= " LEFT JOIN (
SELECT post_id, meta_value as featured_due
FROM $wpdb->postmeta
WHERE meta_key = 'featured' ) AS DD
ON $wpdb->posts.ID = DD.post_id ";
$join .= " LEFT JOIN (
SELECT post_id, meta_value as nard_apply_date_due
FROM $wpdb->postmeta
WHERE meta_key = 'nard_ads_apply_date' ) AS naad
ON $wpdb->posts.ID = naad.post_id ";
Sort code is:
$orderby = " metaKey1 desc, metaKey2 desc, $wpdb->posts.post_date desc ";
But I get wrong order.
My final sql query:
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts
LEFT 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 ( SELECT post_id, meta_value as featured_due FROM wp_postmeta WHERE meta_key = 'featured' ) AS DD
ON wp_posts.ID = DD.post_id LEFT JOIN ( SELECT post_id, meta_value as nard_apply_date_due
FROM wp_postmeta WHERE meta_key = 'nard_ads_apply_date' ) AS naad ON wp_posts.ID = naad.post_id
JOIN ( SELECT post_id FROM wp_postmeta WHERE meta_key = 'custom_field_ID_2' and (meta_value <= 100000000000 and meta_value >= 0)) AS JJ
ON wp_posts.ID = JJ.post_id WHERE 1=1 AND ( wp_term_relationships.term_taxonomy_id IN (72,189,190,191,192,232,233,234) )
AND ( ( wp_postmeta.meta_key = 'closed' AND wp_postmeta.meta_value = '0' ) )
AND wp_posts.post_type = 'project' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private')
AND (1=1 AND (wp_posts.post_title LIKE '%%' OR wp_posts.post_content LIKE '%%') )
GROUP BY wp_posts.ID ORDER BY featured_due desc, nard_apply_date_due desc, wp_posts.post_date desc LIMIT 0, 10
i get result - but it have random order! i want featured_due in first and then nard_apply_date_due
Thanks for your help.