In my database, I have table wp_postmeta
, example:
| meta_key | meta_value | post_id |
---------------------------------
points | 12 | 23
points | 2 | 18
lorem | ipsum | 92
points | 8 | 15
I want to order points
by meta_value
and get the row number of a specific post_id
. Basically a rank system, with highest number at the top.
For example, ordering points
by meta_value
:
| meta_key | meta_value | post_id |
---------------------------------
points | 12 | 23
points | 8 | 15
points | 2 | 18
So, post_id
with value 15
will be rank 2.
What SQL query can I use to achieve this with optimisation in mind?
What I’ve tried so far
So far, I have achieved this via query:
$query="
SELECT post_id,FIND_IN_SET(
post_id,(SELECT GROUP_CONCAT( post_id ORDER BY meta_value * 1 DESC)
FROM $wpdb->postmeta
WHERE meta_key ='points')
) AS `rank`
FROM $wpdb->postmeta
WHERE meta_key ='points'
AND post_id = '".$post_id."'
";
$result = $wpdb->get_row($query);
$rank = $result->rank;
Works fine. However, this query is very slow.
How can I make this query faster?
EDIT: Here is a list of indexes in this table:
3
Answers
For the rest of this problem, a simple bit of php will suffice:
Outputs: 2
Use
ROW_NUMBER()
(orRANK()
if there are ties) window function:If you want the rank of a specific
post_id
:Or:
If
meta_value
where stored as a number, the following might be the fastest approach:This could take advantage of indexes on
wp_postmeta(meta_key, post_id, meta_value)
andwp_postmeta(meta_key, meta_value)
.However,
meta_value
is probably a string so the>
comparison does not work. One option is a generated column, converting the value to a number. I’m not sure if modifying the data model is something you want to do.The goal is to avoid sorting by a non-index key. Another method does something similar, but like this:
with an index on
wp_postmeta(meta_key, post_id, meta_value)
. This should be an index lookup forpm2
and then an index scan for thepoints
records for the outer query.