Поддержка Проблемы и решения Нагрузка на БД можеством циклов в одном шаблоне

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

    Типа:

    <?php query_posts('cat=55&posts_per_page=2&caller_get_posts=1'); ?>
     <?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
    ...
    <?php endif; wp_reset_query(); ?>
    
    <?php query_posts('author=123&&showposts=5'); ?>
     <?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
    ...
    <?php endif; wp_reset_query(); ?>

    Ну и тд. Кол-во таких циклов в шаблоне может быть десяток и более.
    Насколько я понимаю — это создаёт множество запросов к БД.

    Отсюда вопрос: кроме как кешированием — как ещё можно уменьшить кол-во запросов к БД? Мб использование WP_Query будет целесообразней для таких задач (хотя мне видится сложнее в реализации и доп. нагрузке на память)?

Просмотр 15 ответов — с 1 по 15 (всего 17)
  • Давненько уже обсуждали, что query_posts можно использовать только для модификации запроса, а не для создания нового. На эту тему была даже презентация от разработчиков. В общем.. «WP_Query будет целесообразней для таких задач».

    http://wordpress.stackexchange.com/questions/1753/when-should-you-use-wp-query-vs-query-posts-vs-get-posts
    http://wordpress.stackexchange.com/questions/50761/when-to-use-wp-query-query-posts-and-pre-get-posts

    Автор SeVlad

    (@sevlad)

    query_posts можно использовать только для модификации запроса, а не для создания нового.

    Не уверен, что понял эту фразу. Он же вроде как и изменяет, но несколько раз, таким образом создавая новые.

    В общем.. «WP_Query будет целесообразней для таких задач».

    Спасибо, vjpo.
    Правда, в силу отсутствия знаний буржуйского тяжко понять всё написанное, хотя картинка впечатлила 🙂

    Но, с гугпереводом мне показалось что в комментах нет однозначного мнения на этот счёт. Вроде как разницы нет:

    Replacing query_posts() with WP_Query will make no difference in performance, original page’s query will still run because that is part of core load. Those queries will run even if your template file has no loop at all

    (Зато в комментах попалась интересная ссылка. Пока не полностью мой осиленная 😉 )

    Всё же интересует — реально будет выигрыш в производительности и нагрузках или овчинка выделки не стоит? В см. переписывать такое — сизифов труд?

    ЗЫ. В ЧАВО тоже query_posts(). Хотя тут это наверняка из-за простоты реализации.

    Модератор Юрий

    (@yube)

    Я так понимаю, что создавать новый объект класса WP_Query имеет смысл в том случае, если «стартовая» выборка востребована после «кастомной», то есть, имеет место wp_reset_query(). Если же кастомные выборки идут строго после Цикла, то создание еще одного (как минимум) объекта — лишняя трата ресурсов.

    Автор SeVlad

    (@sevlad)

    создавать новый объект класса WP_Query имеет смысл в том случае, если «стартовая» выборка востребована после «кастомной», то есть, имеет место wp_reset_query(). Если же кастомные выборки идут строго после Цикла, то создание еще одного (как минимум) объекта — лишняя трата ресурсов.

    Юрий, сорри, ниасилил Вашу мысль.
    Без wp_reset_query() не будет работать (как нужно) след. в шаблоне query_posts().

    Поэтому, естественно, они идут парами query_posts()wp_reset_query() (как в коде в стартпосте)

    Модератор Юрий

    (@yube)

    Поэтому, естественно, они идут парами query_posts() — wp_reset_query() (как в коде в стартпосте)

    Не естественно 🙂 Reset восстанавливает исходное состояние объекта. Если его восстанавливать не нужно, скажем, если стартовая|инициализационная выборка вообще не используется (мой «любимый» вывод постов на стат. странице) или шаблон сделан так, что все «украшения», требующие выборки постов, идут строго после Цикла, то восстанавливать состояние объекта, то бишь стартовую выборку, вообще нет смысла.

    Модератор Юрий

    (@yube)

    Я, кажется, понял. Похоже, тут играет злую шутку традиционный русский перевод слова «reset» — «сброс». «Сбросу» больше соответствует английское «clear». А «reset» — re set — скорее, повторная установка. То есть, действие конструктивное, а не деструктивное. Sorry, занесло 🙂

    Автор SeVlad

    (@sevlad)

    Юрий, «естественно» было для случая с необходимостью вызова следующего query_posts() 🙂 Т.е. при нескольких выборках. После последнего, конечно, можно и не сбрасывать.. то бишь не (пере)устанавливать в начальное значение.

    Но всё равно я что-то не пойму что Вы хотели сказать по поводу целесообразности использования (и переписывания) query_posts \ WP_Query.

    Модератор Юрий

    (@yube)

    «естественно» было для случая с необходимостью вызова следующего query_posts()

    Сможете обосновать необходимость reset между query_posts? 😉

    Автор SeVlad

    (@sevlad)

    Сможете обосновать необходимость reset между query_posts? 😉

    Эм.. Если не сделать резет, то следующий query_posts (с др. параметрами) выдаст не то, что надо.

    Модератор Юрий

    (@yube)

    Если не сделать резет, то следующий query_posts (с др. параметрами) выдаст не то, что надо.

    Отнюдь! Посмотрите в query.php, что делает wp_reset_query() и её «последователи». Всего лишь возвращают некоторым глобальным переменным те значения, которые были у них на момент, скажем так, начала обработки шаблона вывода.

    Автор SeVlad

    (@sevlad)

    Посмотрите в query.php, что делает wp_reset_query() и её «последователи».

    Посмотрел. Я не насколько хорошо знаю ООП (да и вообще пхп), но

    ==Исправлено==
    насколько я понял, query_posts не «с нуля» создаёт запрос, а суммируется с предыдущим.

    ===

    Юрий, а вообще я это дело как-то испытал на собственной шкуре. Пока не ресетнул (не использовал wp_reset_query()) — не мог добиться корректной выборки следующего query_posts.
    Так что, я согласен с Тимуром (наверное и кодексом 😉 ):

    Функция //речь о wp_reset_query(). SeVlad// не должна использоваться более одного раза на странице. Если вы используете её несколько раз, то используйте wp_reset_query() или пользуйтесь классом wp_query().
    ..
    Если использовать query_posts для создания вторичных циклов, могут появится ошибки (неожиданные результаты) из-за которых будет рушится структура и тип страниц, так как query_posts переписывает базовый запрос, на основе которого определяется тип текущей страницы и многое другое.

    Модератор Юрий

    (@yube)

    Не, ну можно, конечно, и каждый день новую микроволновку покупать, но помыть старую выгоднее ))))

    query_posts можно использовать только для модификации запроса

    В ЧАВО тоже query_posts()

    query_posts($query_string .'&cat=-1');

    Как раз этот случай я имел ввиду как модификация, но был неправ. Codex для модификации запроса strongly рекомендует использовать хук pre_get_posts() т.е. аналог

    function exclude_category( $query ) {
        if ( $query->is_home() && $query->is_main_query() ) {
            $query->set( 'cat', '-1' );
        }
    }
    add_action( 'pre_get_posts', 'exclude_category' );

    Там же о недостатках query_posts()

    It is inefficient (re-runs SQL queries) and will outright fail in some circumstances (especially often when dealing with posts pagination)

    И совсем стронгли:

    don’t use query_posts() ever

    Все это, включая раздел Caveats (предостережения), наводит на мысль, что query_posts хотят положить на полку с биркой «deprecated».

    я это дело как-то испытал на собственной шкуре. Пока не ресетнул (не использовал wp_reset_query()) — не мог добиться корректной выборки следующего query_posts.

    Было дело, и не раз.

    Автор SeVlad

    (@sevlad)

    Codex

    Нда.. первоисточники как всегда рулят. Только жаль, что такие важные страницы не переведены 🙁

    То, что кодекс рекомендует забывать query_posts() — это стало понятно.

    Однако главный вопрос остался:

    реально будет выигрыш в производительности и нагрузках или овчинка выделки не стоит? В см. переписывать такое — сизифов труд?

    И появился новый. Точнее тот же, но к get_posts. Кодекс гласит:

    For general post queries, use WP_Query or get_posts

    Те получается, что существующий в коде query_posts() можно просто заменить get_posts-ом, не изменяя остальной код (ну ещё удалив wp_reset_query()).
    Я правильно понял?

Просмотр 15 ответов — с 1 по 15 (всего 17)
  • Тема «Нагрузка на БД можеством циклов в одном шаблоне» закрыта для новых ответов.