 <p>I have altered the accepted answer's data and query.</p> <p>The data is now a sample of a data from a 5 star rating system.<br> The function now correctly uses average values of all the posts.</p> <p>The difference is in the calculation of those average values, instead PHP, they are calculated in the SQL, for the purpose of the answer.</p> <p><s>You can see it in action on SQL Fiddle: <a href="http://sqlfiddle.com/#!9/84d8b/2/2" rel="nofollow">http://sqlfiddle.com/#!9/84d8b/2/2</a></s></p> <hr> <h2>The updated query</h2> <p>The new fiddle: <a href="http://sqlfiddle.com/#!9/3cdfe/1/2" rel="nofollow">http://sqlfiddle.com/#!9/3cdfe/1/2</a></p> <pre><code>SET @avg_total_votes := (SELECT AVG(meta_value) FROM postmeta WHERE meta_key ='this_num_votes'); SET @avg_total_rating := (SELECT AVG(meta_value) FROM postmeta WHERE meta_key ='this_rating'); SELECT posts.ID, posts.title, getmeta_votes.meta_value AS votes, getmeta_rating.meta_value AS rating, ( ( (@avg_total_votes * @avg_total_rating) + (getmeta_votes.meta_value * getmeta_rating.meta_value) ) / ( @avg_total_votes + getmeta_votes.meta_value ) ) AS factor FROM posts LEFT JOIN postmeta AS getmeta_votes ON posts.ID = getmeta_votes.post_id AND getmeta_votes.meta_key = 'this_num_votes' LEFT JOIN postmeta AS getmeta_rating ON posts.ID = getmeta_rating.post_id AND getmeta_rating.meta_key = 'this_rating' WHERE NOT getmeta_votes.meta_value = 0 AND NOT getmeta_rating.meta_value = 0 ORDER BY factor DESC; </code></pre> <p>I have found this query construction to be much faster, the previous one was working for 2 hours on a 2,000+ posts data set (1,000,000+ wp_postmeta rows), until terminated.</p> <p>This one runs in 0.04 sec.</p>