I am just incredible stupid here as this can be easily done by a simple WP_Query:
new WP_Query( array( 'post_type' => 'shop_order', 'meta_key' => $meta_key, 'meta_value' => $meta_value ) )
However, I decided to compare the actual generated SQL of the get_posts() with a ‘post_where’ filter solution which is:
SELECT wp_posts.ID FROM wp_posts WHERE 1=1 AND wp_posts.post_type="engine" AND ID IN (SELECT post_id FROM wp_postmeta WHERE meta_key = "horsepower" AND meta_value = "275") ORDER BY wp_posts.post_date DESC LIMIT 0, 5
SELECT wp_posts.* FROM wp_posts WHERE ID IN (361,327)
SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE post_id IN (327,361)
with the actual generated SQL of the new WP_Query() solution which is:
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id) WHERE 1=1 AND wp_posts.post_type="engine" AND (wp_posts.post_status="publish" OR wp_posts.post_author = 1 AND wp_posts.post_status="private") AND ( (wp_postmeta.meta_key = 'horsepower' AND CAST(wp_postmeta.meta_value AS CHAR) = '275') ) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 10
SELECT FOUND_ROWS()
SELECT wp_posts.* FROM wp_posts WHERE ID IN (361,327)
SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE post_id IN (327,361)
So, both solutions are roughly equally efficient (the WP_Query() solution is probably slightly faster) but certainly not as efficient as human generated SQL.