get_option() против get_theme_mod(): Почему одна функция медленнее?

18 июл. 2014 г., 23:06:04
Просмотры: 27.7K
Голосов: 22

Я некоторое время использовал get_theme_mod() в различных своих проектах. Я решил воспользоваться преимуществами API настройки тем в WordPress v3.4, как только он стал доступен, поскольку считал его незаменимым инструментом для моих клиентов.

Спустя некоторое время я начал замечать, что мои сайты стали работать немного медленнее обычного, а настройщик тем (Customizer) в частности загружался довольно долго. После множества проб и ошибок во время моего исследования, я решил попробовать изменить type при регистрации настроек (т.е. $wp_customize->add_setting()) с theme_mod на option.

Как только я сделал это и заменил все вызовы get_theme_mod() на get_option(), я заметил очень значительное увеличение скорости при использовании последнего варианта по сравнению с первым как во фронтенде, так и особенно в настройщике тем в административной части. Я просматривал ядро WordPress в попытке найти ответ, почему это происходит, но не смог определить, в чем конкретно заключается проблема в этом сценарии.

Буду признателен за любые идеи от сообщества относительно того, почему get_option() работает значительно быстрее, чем get_theme_mod().

4
Комментарии

Если вы посмотрите в /wp-includes файл option.php, где определена функция get_option(), и файл theme.php, где определена функция get_theme_mod(), вы увидите, что последняя фактически вызывает саму get_option(), выступая как её расширение, которое также применяет необходимые фильтры. Это может объяснить, почему она медленнее.

Jody Heavener Jody Heavener
18 июл. 2014 г. 23:20:51

Джоди, я тоже так думал, но кажется, что простое обращение к get_option() и применение нескольких фильтров не должно замедлять работу настолько значительно, как это было. Конечно, это хорошая отправная точка, но мне интересно, нет ли здесь чего-то ещё.

ntg2 ntg2
19 июл. 2014 г. 19:36:59

Нет никакой причины для какого-либо различия в скорости, поэтому я подозреваю, что что-то другое вызывает ваши наблюдаемые различия. Настройки темы хранятся как обычные опции.

Otto Otto
19 июл. 2014 г. 19:52:00

Может ли процесс сериализации/десериализации при получении отдельной настройки (mod) играть какую-то роль? Мне интересно, может ли эта дополнительная работа по извлечению настройки быть узким местом по сравнению с простым получением опции без необходимости выполнять эти операции. При переходе с get_theme_mod() на get_option() скорость всех проектов в среднем удвоилась как на фронтенде, так и в Customizer. Это было единственное изменение, сделанное для того, чтобы изолировать его от любых других побочных эффектов.

ntg2 ntg2
19 июл. 2014 г. 20:04:47
Все ответы на вопрос 5
0
23

Ответ заключается в том, что да, функции theme_mod будут работать медленнее, но незначительно, и преимущества перевешивают различия.

Настройки темы хранятся как опции. По сути, функции theme_mod являются обертками вокруг функций для работы с опциями.

Сначала нужно понять, что настройки theme_mod хранятся в виде массива в одной опции, привязанной к конкретному имени темы. Например, если я сделаю так:

set_theme_mod('aaa',123);
set_theme_mod('bbb',456);

То в базе данных появится одна строка опции с именем theme_mods_themename, содержащая сериализованный массив с данными ('aaa'=>123, 'bbb'=>456).

Теперь, функция get_theme_mod будет работать медленнее, потому что на самом деле она делает два вызова get_option. Сначала она получает имя темы, затем — опцию theme_mods_themename. Это уже приводит к потере 50% скорости. Остальная работа в основном связана с фильтрами, где есть дополнительный вызов фильтра, но если у вас нет обработчиков для этого фильтра, это несущественно.

Важно отметить, что система опций сохраняет полученные данные в кеше объекта, поэтому здесь не происходит множественных запросов к базе данных. Только первое использование приводит к обращению к базе.

Функция set_theme_mod будет немного медленнее, потому что она делает те же два вызова get_option, затем еще один вызов get_option для повторного получения имени темы, после чего выполняет update_option с полным набором измененных опций. Это приводит к обновлению базы данных, и тот факт, что отправляется гораздо больше данных, действительно может вызвать заметное замедление. Обновление нескольких байт происходит быстрее, чем обновление большой строки. Но разница обычно незначительна. Разве что у вас очень много настроек...

Функции theme_mod, безусловно, требуют оптимизации, но тем не менее их следует использовать вместо get_option и подобных функций из-за дочерних тем.

Проблема с прямым использованием опций заключается в том, что вы работаете с ними напрямую, используя конкретные имена ключей для настроек.

Если у меня есть тема "AAA" и я создаю дочернюю тему "BBB" для другого сайта, то моя тема "AAA" может использовать опцию с именем "example". Когда я обновляю один сайт, и он обновляет мою опцию, то та же опция теперь применится и к моей дочерней теме. А что, если я не хотел этого? Что, если я хочу, чтобы дочерняя тема использовала другой набор настроек?

Theme_mod, включая фактическое имя темы (а не жестко заданное значение) в ключ, гарантирует, что каждая "тема" на сайте использует свой собственный набор настроек. Я могу переключаться между ними, и настройки не переносятся, оставаясь такими, какими я их задал. Это проще, понятнее и интуитивнее.

И если в будущем изменения в ядре или плагины изменят работу theme_mod, вы автоматически получите преимущества без каких-либо изменений. Обертки всегда будут медленнее — это неизбежно, такова их природа. Тем не менее, вы все равно пишете код на PHP, а не на машинном языке. Мы используем такие обертки для упрощения и разделения функциональности. Темы не должны знать или заботиться о том, как их настройки хранятся в базе данных или как работает именование. Функции theme_mod предоставляют более простое и чистое решение.

21 сент. 2014 г. 20:19:21
1

get_theme_mod - это всего лишь обёртка над get_option. Теоретически, из-за дополнительного уровня абстракции, она должна работать медленнее, но на практике разница будет слишком незначительной, чтобы её можно было заметить.

Реальные различия в скорости могут возникать, если у вас есть медленный код, подключённый к хукам theme_mod.

20 июл. 2014 г. 06:11:37
Комментарии

Не обёртка. get_theme_mod сохраняет значение в сериализованном массиве вместе со всеми настройками темы в строке таблицы wp_options с предопределённым ключом "theme_mods_<имя темы>". get_option сохраняет значение в поле option_value строки таблицы wp_options с ключом, который вы указываете. Другими словами, get_theme_mod помещает значение в сериализованный массив со всеми остальными настройками темы; get_option этого не делает.

tklodd tklodd
26 июл. 2022 г. 00:06:38
0

Может быть что-то происходит в Customizer? Я наблюдаю ту же проблему, что и автор оригинального поста.

Могу подтвердить, что при использовании около 30 опций время загрузки Customizer сократилось с примерно 3 секунд до примерно 0.5 секунды при переходе с get_theme_mod на get_option.

При прямом вызове методов разница составляет 2 мс.

Результаты тестирования (https://gist.github.com/anonymous/d98a46d00d52d40e7dec)

Разница может быть незаметна при прямом сравнении API, но должно быть что-то в том, как они используются в Customizer.

22 июл. 2014 г. 00:55:03
1

Вы можете ПРОТЕСТИРОВАТЬ ВРЕМЯ выполнения get_option (100 итераций) с помощью этого кода (поместите его в functions.php или в другое место):

add_action('wp','My_Test');
function My_Test(){
    var_dump(microtime(true));
    for ($i=1; $i<100; $i++) { get_option('blogdescription'); }
    var_dump(microtime(true));
    for ($i=1; $i<100; $i++) { get_theme_mod('blogdescription'); }
    var_dump(microtime(true));
    exit;
}   




Дополнительные размышления

Я не уверен, есть ли разница (возможно, разработчики WordPress знают лучше), но я подумал, что если сайт имеет ВЫСОКИЙ трафик, и при каждой загрузке страницы ему нужно получать сотни опций, то что если я объединю многие опции в одну с помощью get_option? Например, так:

update_option('my_extra_optss',  array(
      'myNAME' => 'Джордж',
      'myAGE'  => 43 ));

Затем:

$x = get_option('my_extra_optss');
$x['myNAME'];
$x['myAGE'];
................

Будет ли это немного ускорять работу сайта?

11 июл. 2015 г. 13:14:12
Комментарии

Это именно то, что уже делает get_theme_mod. Все настройки темы уже объединены в одну опцию. Когда вы вызываете get_theme_mod, при первом обращении происходит два запроса к базе данных, а при последующих вызовах - ноль запросов.

Otto Otto
17 сент. 2016 г. 01:13:29
1

Кратко: Если вы разработчик тем, вам следует использовать get_theme_mod

Подробный ответ:

Если у вас 100 вызовов get_option, это приводит к 100 запросам к вашей базе данных.

Если у вас 100 вызовов get_theme_mod, это приводит всего к 1 запросу к базе данных.

Почему? Потому что все настройки темы хранятся в одной строке базы данных и вызываются только один раз, в то время как каждая опция — это отдельная строка, и 100 вызовов get_option приведут к 100 запросам к базе данных, что, конечно же, замедлит работу вашего сайта.

Если ваша тема имеет много настроек, использование get_theme_mod значительно сократит количество запросов к базе данных.

Вы можете проверить производительность и количество запросов с помощью плагина Query Monitor

9 июл. 2019 г. 07:42:25
Комментарии

Это немного неверно. Функция get_theme_mod использует get_theme_mods - https://developer.wordpress.org/reference/functions/get_theme_mods/ - которая фактически выполняет 2 функции get_option. Таким образом, 100 вызовов get_theme_mod делают всего 2 запроса к базе данных ;)

WPExplorer WPExplorer
15 апр. 2020 г. 01:58:35