It seems you are trying to obtain a result set with one row per post of type car
. It seems you want to display various attributes of each car in the post, and those are stashed away in postmeta
.
Pro tip: Never use SELECT *
in software unless you absolutely know why you're doing it. Especially with queries containing lots of JOIN
operations, SELECT *
returns lots of pointless and redundant columns.
There's a query design trick to know for the WordPress postmeta
table. If you want to get a particular attribute, do this:
SELECT p.ID, p.post_title,
color.meta_value AS color
FROM wp_posts AS p
LEFT JOIN wp_postmeta AS color ON p.ID = color.post_id AND 'color' = color.meta_key
WHERE p.post_status = 'publish'
AND /* etc etc */
It's super-important to understand this pattern when doing what you're trying to do. This pattern is required because postmeta
is a peculiar type of table called a key-value or entity-attribute-value store. What's going on here? A few things:
- Using this pattern uou get one row for each post, with some columns from the
posts
table and a particular attribute from the postmeta
table.
- You are
LEFT JOIN
ing the postmeta
table so you still get a row if the attribute is missing.
- You are using an alias name for the
postmeta
table. Here it's postmeta AS color
.
- You are including the selector for
meta_key
(here it's 'color' = color.meta_key
) in the ON
condition of the join.
- You are using an alias in your
SELECT
clause to present the postmeta.meta_value
item with an appropriate column name. Here it's color.meta_value AS color
.
Once you get used to employing this pattern, you can stack it up, with a cascade of LEFT JOIN
operations, to get lots of different attributes, like so.
SELECT wp_posts.ID, wp_posts.post_title, wp_posts.whatever,
color.meta_value AS color,
transmission.meta_value AS transmission,
model.meta_value AS model,
brand.meta_value AS brand
FROM wp_posts
LEFT JOIN wp_postmeta AS color
ON wp_posts.ID = color.post_id AND color.meta_key='color'
LEFT JOIN wp_postmeta AS transmission
ON wp_posts.ID = transmission.post_id AND transmission.meta_key='transmission'
LEFT JOIN wp_postmeta AS model
ON wp_posts.ID = model.post_id AND model.meta_key='model'
LEFT JOIN wp_postmeta AS brand
ON wp_posts.ID = brand.post_id AND brand.meta_key='brand'
WHERE wp_posts.post_status = 'publish'
AND wp_posts.post_type = 'car'
ORDER BY wp_posts.post_title
I've done a bunch of indenting on this query to make it easier to see the pattern. You may prefer a different indenting style.
It's hard to know why you were having performance problems with the query in your question. It's possibly because you were getting a combinatorial explosion with all the INNER JOIN
operations that was then filtered. But at any rate the query you showed was probably returning no rows.
If you are still having performance trouble, try creating a compound index on postmeta
on the (post_id, meta_key, meta_value)
columns. If you're creating a WordPress plugin, that's probably a job to do at plugin installation time.