Rewriting INNER JOIN-filled MySQL with reduced complexity?

123 Views Asked by At

I am trying to extract all users, including some metadata, and want to filter them based on some other metadata.

Two tables are involved: wp_user, with ID as the only relevant field, and wp_usermeta:

umeta_id | user_id | meta_key | meta_value.

My current solution looks as follows:

I INNER JOIN the users with the specific usermeta entries that match the keys I want to filter against. The filtering is then done through a WHERE where I compare (using LIKE) these meta_values against a number of strings.

The result:

A number of rows, with one row per user that passed the filtering (its meta values matched the LIKEs successfully).

The problem:

This works, I do get the result I need. But already, with only a few users (and thus ~100 rows in usermeta), the query takes ~2 seconds. The complexity of the query is scary. How can I rewrite this SQL to get the same result, but without the bad scaling potential?

I've tried:

It makes sense to join the usermeta only once. I can make one single INNER JOIN, but this gives me several rows for every user in the result. And I don't know how that would function together with the filtering either. I've also tried reading about GROUP and CONCAT features, but my MySQL knowledge is not high enough to figure it out on my own.

The SQL:

SELECT 
    u.ID as ID, 
    um_6.meta_value,
    um_7.meta_value,
    um_8.meta_value,
    um_9.meta_value
FROM 
    wp_users u

INNER JOIN wp_usermeta um_1  ON u.ID=um_1.user_id AND um_1.meta_key  = "meta_key_1"
INNER JOIN wp_usermeta um_2  ON u.ID=um_2.user_id AND um_2.meta_key  = "meta_key_2"
INNER JOIN wp_usermeta um_3  ON u.ID=um_3.user_id AND um_3.meta_key  = "meta_key_3"
INNER JOIN wp_usermeta um_4  ON u.ID=um_4.user_id AND um_4.meta_key  = "meta_key_4"
INNER JOIN wp_usermeta um_5  ON u.ID=um_5.user_id AND um_5.meta_key  = "meta_key_5"
INNER JOIN wp_usermeta um_6  ON u.ID=um_6.user_id AND um_6.meta_key  = "meta_key_6"
INNER JOIN wp_usermeta um_7  ON u.ID=um_7.user_id AND um_7.meta_key  = "meta_key_7"
INNER JOIN wp_usermeta um_8  ON u.ID=um_8.user_id AND um_8.meta_key  = "meta_key_8" 
INNER JOIN wp_usermeta um_9  ON u.ID=um_9.user_id AND um_9.meta_key  = "meta_key_9"

WHERE 
( um_1.meta_value LIKE "%example_value_1%" ) AND 
( um_2.meta_value LIKE "%example_value_2%" ) AND 
( um_3.meta_value LIKE "%example_value_3%" ) AND
( um_4.meta_value LIKE "%example_value_4%" ) AND

(
    um_5.meta_value LIKE "%string_1%" OR 
    um_5.meta_value LIKE "%string_2%" OR 
    um_5.meta_value LIKE "%string_3%" OR 
    um_5.meta_value LIKE "%string_4%"
)
0

There are 0 best solutions below