I am working on a real estate WP site that has a search function.
Users can chose different options to refine the houses shown to them.
There are options like land size, garage type, number of bedrooms etc.
Now if a user selects a lot of options, the mysql query becomes so large that it crashes the server. The website goes down for several minutes.
Today we were contacted by the web-hoster and asked to optimize this query, or they'll disable our website. They also sent me the raw query (attached underneath)
The query is being build in WP style like so:
$args = array(
'post_type' => 'house',
'paged' => get_query_var('paged'),
'tax_query' => array(
array(
'taxonomy' => $acf_housepage_category->taxonomy,
'field' => 'slug',
'terms' => $acf_housepage_category->slug,
),
),
'meta_query' => $meta_query,
);
While $meta_query is an array of meta field names/values.
Eventually, the raw query looks like this:
SELECT SQL_CALC_FOUND_ROWS wp_s3mv0r_posts.ID FROM wp_s3mv0r_posts INNER JOIN wp_s3mv0r_term_relationships ON (wp_s3mv0r_posts.ID = wp_s3mv0r_term_relationships.object_id) INNER JOIN wp_s3mv0r_postmeta ON ( wp_s3mv0r_posts.ID = wp_s3mv0r_postmeta.post_id ) INNER JOIN wp_s3mv0r_postmeta AS mt1 ON ( wp_s3mv0r_posts.ID = mt1.post_id ) INNER JOIN wp_s3mv0r_postmeta AS mt2 ON ( wp_s3mv0r_posts.ID = mt2.post_id ) INNER JOIN wp_s3mv0r_postmeta AS mt3 ON ( wp_s3mv0r_posts.ID = mt3.post_id ) INNER JOIN wp_s3mv0r_postmeta AS mt4 ON ( wp_s3mv0r_posts.ID = mt4.post_id ) INNER JOIN wp_s3mv0r_postmeta AS mt5 ON ( wp_s3mv0r_posts.ID = mt5.post_id ) INNER JOIN wp_s3mv0r_postmeta AS mt6 ON ( wp_s3mv0r_posts.ID = mt6.post_id ) INNER JOIN wp_s3mv0r_postmeta AS mt7 ON ( wp_s3mv0r_posts.ID = mt7.post_id ) INNER JOIN wp_s3mv0r_postmeta AS mt8 ON ( wp_s3mv0r_posts.ID = mt8.post_id ) INNER JOIN wp_s3mv0r_postmeta AS mt9 ON ( wp_s3mv0r_posts.ID = mt9.post_id ) INNER JOIN wp_s3mv0r_postmeta AS mt10 ON ( wp_s3mv0r_posts.ID = mt10.post_id ) INNER JOIN wp_s3mv0r_postmeta AS mt11 ON ( wp_s3mv0r_posts.ID = mt11.post_id ) INNER JOIN wp_s3mv0r_postmeta AS mt12 ON ( wp_s3mv0r_posts.ID = mt12.post_id ) WHERE 1=1 AND (
wp_s3mv0r_term_relationships.term_taxonomy_id IN (11,24,25)
) AND (
( wp_s3mv0r_postmeta.meta_key = 'acf_house_minprice' AND CAST(wp_s3mv0r_postmeta.meta_value AS SIGNED) BETWEEN '274990' AND '599990' )
AND
( mt1.meta_key = 'acf_house_minlotwidth' AND CAST(mt1.meta_value AS SIGNED) BETWEEN '16' AND '16' )
AND
( mt2.meta_key = 'acf_location_area' AND CAST(mt2.meta_value AS CHAR) IN ('South of river') )
AND
( mt3.meta_key = 'acf_house_bedroom' AND CAST(mt3.meta_value AS CHAR) = '4' )
AND
( mt4.meta_key = 'acf_house_studyroom' AND CAST(mt4.meta_value AS SIGNED) > '0' )
AND
( mt5.meta_key = 'acf_house_theaterroom' AND CAST(mt5.meta_value AS SIGNED) > '0' )
AND
( mt6.meta_key = 'acf_house_alfresco' AND CAST(mt6.meta_value AS SIGNED) > '0' )
AND
( mt7.meta_key = 'acf_house_activityroom' AND CAST(mt7.meta_value AS SIGNED) > '0' )
AND
( mt8.meta_key = 'acf_house_doublegarage' AND CAST(mt8.meta_value AS SIGNED) > '0' )
AND
( mt9.meta_key = 'acf_house_reargarage' AND CAST(mt9.meta_value AS SIGNED) > '0' )
AND
( mt10.meta_key = 'acf_house_islbeninkitchen' AND CAST(mt10.meta_value AS SIGNED) > '0' )
AND
( mt11.meta_key = 'acf_house_frontmasterbedroom' AND CAST(mt11.meta_value AS SIGNED) > '0' )
AND
( mt12.meta_key = 'acf_house_rearmaster' AND CAST(mt12.meta_value AS SIGNED) > '0' )
) AND wp_s3mv0r_posts.post_type = 'house' AND (wp_s3mv0r_posts.post_status = 'publish') GROUP BY wp_s3mv0r_posts.ID ORDER BY wp_s3mv0r_posts.post_date DESC LIMIT 0, 10
Are there ways to make this query easier on the server?
E.g. reduce the number of inner joins?
Or select a bunch of posts first and then refine them further with another query?