Администратор: очень медленное редактирование страницы, вызванное основным мета-запросом

11

Мы замечали очень долгое время загрузки при редактировании поста или страницы. Используя Query Monitor, мы обнаружили, что этот основной запрос WP занимает до 15-20 секунд.

SELECT meta_key 
FROM wp_postmeta 
GROUP BY meta_key 
HAVING meta_key NOT LIKE '\\_%' 
ORDER BY meta_key 
LIMIT 30

caller: 
meta_form()
post_custom_meta_box()
do_meta_boxes()

Мы используем много постметов, так как один из наших типов постов использует около 20 или около того пользовательских полей. Я бы сказал, может быть, мы слишком полагаемся на postmeta, но это кажется очень неэффективным запросом, поскольку он даже не выбирает идентификатор сообщения.

Это общая проблема? Есть ли способ отключить эту функцию через фильтр? Спасибо за любой вклад.

psorensen
источник
Это происходит без каких-либо плагинов и темы по умолчанию?
Биргире
Да. Как уже упоминалось выше, я определил медленный запрос как принадлежащий ядру WP. С помощью функции в ответе, которую я предоставил, мета-поле пользовательских полей отключено, что препятствует выполнению запроса.
psorensen
2
Я знаю, я только что проверил meta_form()функцию, и это действительно сгенерированный запрос SQL из этой основной функции. Вы можете попытаться добавить свой собственный метабокс с изменениями в коде meta_form()и использовать предложенный SQL-запрос. Я нашел этот закрытый билет # 8561 . Возможно, вы могли бы создать еще один билет или попытаться снова открыть этот? PS: обратите внимание, что выбор метабокса для родительской страницы также проблематичен. Если у вас есть 1 миллион страниц, то все они будут отображаться как выбранные варианты!
Биргире
2
Решение , предложенное на CSS-Tricks: css-tricks.com/...
psorensen
Интересное решение есть, но похоже, что оно заменяет всю meta_form()функцию. Я обновил ответ - основной запрос SQL был скорректирован в WP версии 4.3. Видите ли вы какой-либо выигрыш в производительности с этим новым запросом SQL по сравнению с нашими дополнительными post_idограничениями?
Birgire

Ответы:

5

Если вы хотите проверить свой пользовательский SQL, чтобы увидеть, как он влияет на время загрузки, вы можете попробовать поменять местами этот запрос:

/**
 * Restrict the potential slow query in the meta_form() to the current post ID.
 *
 * @see http://wordpress.stackexchange.com/a/187712/26350
 */

add_action( 'add_meta_boxes_post', function( $post )
{
    add_filter( 'query', function( $sql ) use ( $post )
    {
        global $wpdb;
        $find = "SELECT meta_key
                 FROM $wpdb->postmeta
                 GROUP BY meta_key 
                 HAVING meta_key NOT LIKE '\\\_%'
                 ORDER BY meta_key 
                 LIMIT 30";
        if(    preg_replace( '/\s+/', ' ', $sql ) === preg_replace( '/\s+/', ' ', $find )
            && $post instanceof WP_Post  
        ) {
            $post_id = (int) $post->ID;
            $sql  = "SELECT meta_key
                     FROM $wpdb->postmeta
                     WHERE post_id = {$post_id}
                     GROUP BY meta_key
                     HAVING meta_key NOT LIKE '\\\_%'
                     ORDER BY meta_key
                     LIMIT 30";
        }
        return $sql;
    } );                                                            
} );

Здесь мы используем add_meta_boxes_{$post_type}крюк, где $post_type = 'post'.

Здесь мы поменяем местами весь запрос, но мы могли бы также настроить его для поддержки динамического ограничения.

Надеюсь, вы можете настроить это в соответствии с вашими потребностями.

Обновить:

Этот потенциально медленный запрос ядра SQL теперь был изменен в WP версии 4.3 с

SELECT meta_key 
FROM wp_postmeta 
GROUP BY meta_key 
HAVING meta_key NOT LIKE '\\_%' 
ORDER BY meta_key 
LIMIT 30

чтобы:

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;

Проверьте основной билет # 24498 для получения дополнительной информации.

birgire
источник
2

Если вы просмотрите исходный код функции, вы найдете это:

$keys = apply_filters( 'postmeta_form_keys', null, $post );
if ( null === $keys ) {
    ...      
}

Используя postmeta_form_keysхук, вы можете вручную указать ключи, чтобы вообще не вызывать этот неэффективный запрос:

add_filter('postmeta_form_keys', function(){
    return ['your_meta_key'];
});
Дэн К
источник
Интересно. Где в исходном коде это существует?
psorensen
wp-admin / includes / template.php: 595 с 4.4
markdwhite
2

Можете ли вы попробовать это. Это не решение, а временное решение.

// disable big slowdown http://wordpress.stackexchange.com/questions/187612/admin-very-slow-edit-page-caused-by-core-meta-query
function dj_limit_postmeta( $string, $post ) {
    return array(null);
}
add_filter( 'postmeta_form_keys', 'dj_limit_postmeta', 10, 3 );
прости
источник
-1

Удаление метабоксов также предотвращает медленный запрос.

function remove_metaboxes() {
     remove_meta_box( 'postcustom', 'page', 'normal' );
}
add_action('admin_menu', 'remove_metaboxes');
psorensen
источник