Make WordPress Core


Ignore:
Timestamp:
01/15/2025 10:11:15 PM (20 months ago)
Author:
peterwilsoncc
Message:

Options/Meta APIs: Optimize cache hits for non-existent options.

Optimize the order of checking the various options caches in get_option() to prevent hitting external caches each time it is called for a known non-existent option.

The caches are checked in the following order when getting an option:

  1. Check the alloptions cache first to prioritize existing loaded options.
  2. Check the notoptions cache before a cache lookup or DB hit.
  3. Check the options cache prior to a DB hit.

Follow up to [56595].

Props adamsilverstein, flixos90, ivankristianto, joemcgill, rmccue, siliconforks, spacedmonkey.
Fixes #62692.
See #58277.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/option.php

    r59373 r59631  
    163163        if ( ! wp_installing() ) {
    164164                $alloptions = wp_load_alloptions();
    165 
     165                /*
     166                 * When getting an option value, we check in the following order for performance:
     167                 *
     168                 * 1. Check the 'alloptions' cache first to prioritize existing loaded options.
     169                 * 2. Check the 'notoptions' cache before a cache lookup or DB hit.
     170                 * 3. Check the 'options' cache prior to a DB hit.
     171                 * 4. Check the DB for the option and cache it in either the 'options' or 'notoptions' cache.
     172                 */
    166173                if ( isset( $alloptions[ $option ] ) ) {
    167174                        $value = $alloptions[ $option ];
    168175                } else {
     176                        // Check for non-existent options first to avoid unnecessary object cache lookups and DB hits.
     177                        $notoptions = wp_cache_get( 'notoptions', 'options' );
     178
     179                        if ( ! is_array( $notoptions ) ) {
     180                                $notoptions = array();
     181                                wp_cache_set( 'notoptions', $notoptions, 'options' );
     182                        }
     183
     184                        if ( isset( $notoptions[ $option ] ) ) {
     185                                /**
     186                                 * Filters the default value for an option.
     187                                 *
     188                                 * The dynamic portion of the hook name, `$option`, refers to the option name.
     189                                 *
     190                                 * @since 3.4.0
     191                                 * @since 4.4.0 The `$option` parameter was added.
     192                                 * @since 4.7.0 The `$passed_default` parameter was added to distinguish between a `false` value and the default parameter value.
     193                                 *
     194                                 * @param mixed  $default_value  The default value to return if the option does not exist
     195                                 *                               in the database.
     196                                 * @param string $option         Option name.
     197                                 * @param bool   $passed_default Was `get_option()` passed a default value?
     198                                 */
     199                                return apply_filters( "default_option_{$option}", $default_value, $option, $passed_default );
     200                        }
     201
    169202                        $value = wp_cache_get( $option, 'options' );
    170203
    171204                        if ( false === $value ) {
    172                                 // Prevent non-existent options from triggering multiple queries.
    173                                 $notoptions = wp_cache_get( 'notoptions', 'options' );
    174 
    175                                 // Prevent non-existent `notoptions` key from triggering multiple key lookups.
    176                                 if ( ! is_array( $notoptions ) ) {
    177                                         $notoptions = array();
    178                                         wp_cache_set( 'notoptions', $notoptions, 'options' );
    179                                 } elseif ( isset( $notoptions[ $option ] ) ) {
    180                                         /**
    181                                          * Filters the default value for an option.
    182                                          *
    183                                          * The dynamic portion of the hook name, `$option`, refers to the option name.
    184                                          *
    185                                          * @since 3.4.0
    186                                          * @since 4.4.0 The `$option` parameter was added.
    187                                          * @since 4.7.0 The `$passed_default` parameter was added to distinguish between a `false` value and the default parameter value.
    188                                          *
    189                                          * @param mixed  $default_value  The default value to return if the option does not exist
    190                                          *                               in the database.
    191                                          * @param string $option         Option name.
    192                                          * @param bool   $passed_default Was `get_option()` passed a default value?
    193                                          */
    194                                         return apply_filters( "default_option_{$option}", $default_value, $option, $passed_default );
    195                                 }
    196205
    197206                                $row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
Note: See TracChangeset for help on using the changeset viewer.