[wp-trac] [WordPress Trac] #33885: meta_form performs a potentially expensive query

WordPress Trac noreply at wordpress.org
Thu Aug 26 11:43:12 UTC 2021


#33885: meta_form performs a potentially expensive query
-------------------------------------------------+-------------------------
 Reporter:  jorbin                               |       Owner:  (none)
     Type:  defect (bug)                         |      Status:  new
 Priority:  normal                               |   Milestone:  Future
                                                 |  Release
Component:  Administration                       |     Version:  4.3.1
 Severity:  critical                             |  Resolution:
 Keywords:  has-patch needs-testing needs-unit-  |     Focuses:
  tests                                          |  performance
-------------------------------------------------+-------------------------

Comment (by OllieJones):

 Coming late to this tix, with some MySQL / MariaDB optimization
 experience.

 **tl;dr: Don't change the MySQL column definitions in core. Address
 performance issues by changing keys (indexes) instead.**

 Here's an explanation of the situation from my perspective. Key/value
 tables like `postmeta` are among the trickiest to optimize in the world of
 SQL. But, of course they allow wide-open extension and creativity. If
 every custom field required a database schema change, well, we probably
 wouldn't have heard of WordPress in 2021. WordPress wouldn't be as wildly
 successful as it is without `postmeta` (and `usermeta`, `termmeta`). So
 our challenge as WordPress.org site operators and developers is to make
 those tables work well at scale. (They already work fine for smaller
 installations.)

 The slow query that's the topic of this tix is

 {{{
 SELECT DISTINCT meta_key
   FROM wp_postmeta
  WHERE meta_key NOT BETWEEN '_' AND '_z'
 HAVING meta_key NOT LIKE '\\_%'
  ORDER BY meta_key
  LIMIT 30
 }}}


 When the table index ("table key" in common WP parlance) is a ''prefix
 index'' such as `wp_postmeta(meta_key(191))` it's useful for satisfying
 WHERE clauses like `WHERE meta_key NOT BETWEEN '_' AND '_z'`: it serves to
 locate the correct rows of the table to use. MySQL uses the index to grab
 the rows and then doublechecks the filter condition against the contents
 of the row.

 But when the index is like `wp_postmeta(meta_key)` (not a prefix index),
 the index *covers* the query
 [https://dev.mysql.com/doc/refman/8.0/en/glossary.html#glos_covering_index]
 in question.  That is, the query can be satisfied directly from the index.
 That makes this particular query almost miraculously fast. These BTREE
 indexes are already in the right order for `ORDER BY`. `ORDER BY ...
 LIMIT...` is a notorious way to make your MySQL query slow except in the
 cases like this where it can exploit a covering index.

 Here's the thing:  This query is a special case: it only handles one
 column of one table. So, making a covering index just for it then saying
 "wow that's fast! problem solved!"  isn't sufficient justification for a
 core table change.

 I do not believe it's a good idea to change the definition of the table
 from `meta_key VARCHAR(250)` to `191`. Others have pointed out this will
 break some of the zillions of WordPress installations out there, and I
 agree. Plus, the discipline of database administration says "don't change
 the data. change the indexes".

 Good covering indexes often are *compound indexes* indexing multiple
 columns. And they often serve to optimize multiple query patterns, not
 just one.

 Recent MySQL versions (specifically those with the InnoDB Barracuda
 engine) don't have the 767-byte limit on indexes: it's 3072
 [https://dev.mysql.com/doc/refman/5.7/en/innodb-limits.html]. Barracuda
 has been available since MySQL 5.7, with some versions of 5.6 also
 supporting it. MariaDB 10.2 and beyond supports Barracuda too.  So the
 prefix indexes aren't necessary any more.

 If any change is necessary in core, it's to the indexes not the tables.
 Rick James and I have been working on a plugin to reindex the `*meta`
 tables and a few others. [https://wordpress.org/plugins/index-wp-mysql-
 for-speed/]. It's still pretty new, but it seems to help. It helps users
 upgrade from MyISAM to InnoDB, then adds some compound indexes. You can
 read about the theory of operation. here.
 [https://www.plumislandmedia.net/wordpress/speeding-up-wordpress-database-
 operations/]

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/33885#comment:86>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list