Make WordPress Core

Opened 7 weeks ago

Closed 4 weeks ago

Last modified 3 weeks ago

#58962 closed enhancement (fixed)

Provide a way to load multiple specific options with a single database request

Reported by: flixos90's profile flixos90 Owned by: flixos90's profile flixos90
Milestone: 6.4 Priority: normal
Severity: normal Version:
Component: Options, Meta APIs Keywords: has-patch has-unit-tests needs-dev-note
Focuses: performance Cc:

Description

WordPress's get_option() function generally relies on making individual database requests for each option, however with the majority of options (in most cases) being autoloaded, i.e. fetched once with a single database request and then stored in (memory) cache.

The option autoloading approach has been helpful overall in minimizing database requests, however for many sites "excessive autoloading" (i.e. autoloading too many options) has led to problems, where lots of options are loaded in the frontend that are never used during these pageloads, which slows down load time performance. Sometimes the issue is even worse to the degree that certain object cache solutions cannot store the large amount of data anymore, which can lead to extremely slow performance due to the bug.

Part of the problem is lack of documentation around option autoloading, its implications and best practices. For example, options that are only used in very specific contexts, e.g. a specific WP Admin screen, should preferably not be autoloaded. Though as of today, while preferable from an overall performance perspective, there is a lack of alternatives for use-cases where multiple options are still needed: For example, if a plugin needs to load 5-10 options on their own WP Admin screen, simply recommending to not autoload them would lead to 5-10 database requests on that WP Admin screen, i.e. unnecessarily slowing down performance of that screen.

Therefore this ticket aims to provide a way to load (or prime in cache) multiple specific options with a single database request. This can be used as a reasonable alternative for use-cases like the above, encouraging to not use general option autoloading as a bandaid for the lack of another efficient way to load multiple options.

Change History (12)

#1 @flixos90
7 weeks ago

  • Keywords needs-patch needs-unit-tests added

To address this problem, we have holistically two options: Either we provide a way to directly retrieve multiple options at once, e.g. a get_options( $options ) function. Or we stick to focusing on the existing get_option() for actually retrieving options, but provide a function to prime specific options, i.e. load them into the cache with a single database request - similarly to the autoloaded options ("alloptions") query, but for a specific set of options.

I would propose the following solution to the problem:

  • Implement a function prime_options( $options ) to which developers can pass an array of option names. The function will load all options into the cache with a single database query, except for those options that are already in cache (if any).
  • With this function, a plugin for example could call it when its WP Admin screen is loaded, priming all its options in a single database query. It could then potentially update these options to use $autoload = 'no'. No changes would need to be made to how options are actually fetched, as get_option() would function the same way as before - the values would simply be already in cache if primed before.

The above function would be the central foundation, however we could consider implementing additional "wrapper" functions to facilitate specific use-cases, for example:

  • A prime_options_by_group( $option_group ) may be useful as a wrapper for prime_options(), allowing e.g. a plugin to prime all options registered with a specific option group. This would give the benefit of not having to remember/hard-code all option names in the priming function call, and it would tie in nicely with the existing Settings API, where option names have been a required parameter since its origin. The function would effectively get all option names in the given group and then call prime_options( $options ) with them.
  • A get_options( $options ) function may be useful to actually retrieve multiple options in one go. The function would effectively call prime_options( $options ) and then get_option( $option ) for each of them, returning an array of key value pairs.

While we could also implement a standalone get_options( $options ) function as an alternative (i.e. not using another function to prime options), I consider that approach overly limiting, as it would require to basically duplicate lots of the get_option() function's code, and it would be easy to miss some nuances. So focusing the new functionality on priming options while keeping the foundation for retrieving options untouched makes more sense IMO.

This ticket was mentioned in PR #4970 on WordPress/wordpress-develop by @mukesh27.


6 weeks ago
#2

  • Keywords has-patch added; needs-patch removed

Trac ticket: https://core.trac.wordpress.org/ticket/58962

This pull request adds new functions as described in the issue description. Once we agree with the functions' code and signature, I will add unit tests.

  • [ ] Add tests to cover the change.

#3 @mukesh27
6 weeks ago

Thanks @flixos90 for the details. I have raise PR that add requested functions.

@mukesh27 commented on PR #4970:


6 weeks ago
#4

@felixarntz PR is ready for review.

#5 @mukesh27
6 weeks ago

  • Keywords has-unit-tests added; needs-unit-tests removed

@mukesh27 commented on PR #4970:


5 weeks ago
#6

Thank you, @felixarntz, for the detailed code review and unit tests assessment. I have addressed those in my recent commit.

@costdev, I appreciate your explanation on Slack regarding the points I had misunderstood. 🦸‍♂️

@mukesh27 commented on PR #4970:


5 weeks ago
#7

Thank you, @felixarntz, for addressing the questions posed by @joemcgill. I concur with your responses. Joe, could you kindly review them when you have a moment today, so that we may proceed with the commit. Many thanks!

@mukesh27 commented on PR #4970:


4 weeks ago
#8

Thanks @joemcgill and @felixarntz 👏

#9 @flixos90
4 weeks ago

  • Resolution set to fixed
  • Status changed from assigned to closed

In 56445:

Options, Meta APIs: Introduce prime_options() to load multiple options with a single database request.

WordPress's get_option() function generally relies on making individual database requests for each option, however with the majority of options (in most cases) being autoloaded, i.e. fetched once with a single database request and then stored in (memory) cache.

As part of a greater effort to reduce the amount of options that are unnecessarily autoloaded, this changeset introduces an alternative way to retrieve multiple options in a performant manner, with a single database request. This provides a reasonable alternative for e.g. plugins that use several options which only need to be loaded in a few specific screens.

Specifically, this changeset introduces the following functions:

  • prime_options( $options ) is the foundation to load multiple specific options with a single database request. Only options that aren't already cached (in alloptions or an individual cache) are retrieved from the database.
  • prime_options_by_group( $option_group ) is a convenience wrapper function for the above which allows to prime all options of a specific option group (as configured via register_setting()).
  • get_options( $options ) is another wrapper function which first primes the requested options and then returns them in an associative array, calling get_option() for each of them.

Props mukesh27, joemcgill, costdev, olliejones.
Fixes #58962.

#11 @flixos90
4 weeks ago

  • Keywords needs-dev-note added

This ticket was mentioned in Slack in #core by joemcgill. View the logs.


3 weeks ago

Note: See TracTickets for help on using tickets.