Opened 5 years ago
Last modified 3 months ago
#45354 new enhancement
Adding index for meta_key and post_id in postmeta
Reported by: |
|
Owned by: | |
---|---|---|---|
Milestone: | Awaiting Review | Priority: | normal |
Severity: | normal | Version: | |
Component: | Database | Keywords: | needs-testing dev-feedback |
Focuses: | performance | Cc: |
Description
We should add an index on post_id and meta_key as queries that contain these columns are incredibly common (even in loop in core on every page load basically).
An index will improve query speed up to 100% even when only 1000 posts are in db.
Test it yourself:
ALTER TABLE `wp_postmeta` ADD INDEX `wp_postmeta_key_id` (`meta_key`,`post_id`);
Change History (9)
#2
in reply to:
↑ 1
@
5 years ago
No, my code is the fix/patch for the problem.
For query example take the loop query (which gets post_id and _visibility for example).
But most WP core but also plugin queries like woocommerce,... will profit immensely from this index, as they select post_id inner join on postmeta where meta_key
#3
@
5 years ago
I can confirm that adding such might improve performance on many plugins.
Let's take imagify for example (with 100000 attachment in database).
Query:
SELECT SQL_NO_CACHE count(1) FROM wp_posts AS p INNER JOIN wp_postmeta AS imrwpmt1 ON ( p.ID = imrwpmt1.post_id AND imrwpmt1.meta_key = '_wp_attached_file' ) INNER JOIN wp_postmeta AS imrwpmt2 ON ( p.ID = imrwpmt2.post_id AND imrwpmt2.meta_key = '_wp_attachment_metadata' ) INNER JOIN wp_postmeta AS mt1 ON ( p.ID = mt1.post_id AND mt1.meta_key = '_imagify_status' ) WHERE p.post_mime_type IN ( 'image/jpeg','image/png','image/gif','application/pdf' ) AND p.post_type = 'attachment' AND p.post_status IN ( 'inherit','private' ) AND mt1.meta_value IN ( 'success', 'already_optimized' ) AND imrwpmt1.meta_value NOT LIKE '%://%' AND imrwpmt1.meta_value NOT LIKE '_:\\\%' AND ( LOWER( imrwpmt1.meta_value ) LIKE '%.jpg' OR LOWER( imrwpmt1.meta_value ) LIKE '%.jpeg' OR LOWER( imrwpmt1.meta_value ) LIKE '%.jpe' OR LOWER( imrwpmt1.meta_value ) LIKE '%.png' OR LOWER( imrwpmt1.meta_value ) LIKE '%.gif' OR LOWER( imrwpmt1.meta_value ) LIKE '%.pdf' );
a) default wordpress indexes:
1 row in set (28.22 sec)
b) after adding post_id + meta_key index
ALTER TABLE wp_postmeta ADD INDEX( `post_id`, `meta_key`);
1 row in set (2.51 sec)
It could be 10 times faster in some situations.
#5
@
2 years ago
I'd say an index like this is beneficial if it helps frontend visitors, or if it helps backend users without causing any frontend delays. With the wide variety of plugins that use post meta, this may be difficult to determine, so maybe site admins should consider this on a site-by-site basis.
@fliespl @DuckDagobert Have you tested both "post_id, meta_key" and "meta_key, post_id" to see which one is faster? These columns vary in cardinality and speed of comparison, so one may be better than the other.
Also, have you measured the impact on both frontend and backend? Can you share more contextual details?
#6
@
4 months ago
What are the potential downsides of this - why this has not been added in WP db upgrades?
#7
@
4 months ago
An additional index means slower updates and slightly slower queries that don't use the index (more decisions to make on the best query plan). On sites that update meta data a lot, or sites that don't use this index much, this may not be of benefit.
Also, as I've mentioned, the index can be created in 2 ways, and this will yield different results - one may help more and one may hinder more. It really depends on the context.
Looking at the very commonly-used core functions for getting meta data, they seem to fetch all the meta data of specific IDs into a cache at once, and then grab specific values from that cache by the key, so an index on the meta key will not help speed this up.
And index on post_id, meta_key
would speed things up if WordPress fetched single records by the post ID and meta key.
Core Team, am I reading this correctly? Because this could be the start of a course change that will bring much performance improvement.
Importantly, if access to wp_postmeta
is done by post_id
, the table should have a primary index in that field, and it's currently indexed by meta_id
, which doesn't help much.
A primary index by post_id
should be lightning fast, because all the meta data records for a given ID would be contiguous and require the smallest possible number of block fetches in the database.
@DuckDagobert when we have to call above sql query in core software?