Как повысить эффективность моего сервера WordPress GraphQL для статического веб-сайта

Я недавно создал инструмент создания схемы graphql, который проверяет представление JSON набора расширенных настраиваемых полей WordPress для сгенерировать схему graphql. Представление JSON основано на настраиваемых типах сообщений и расширенных настраиваемых полях, имеющихся в базе данных SQL.

Например, определение настраиваемого типа сообщения с именем Office Location с настраиваемыми полями city и street_address приводит к схеме graphql, которую можно запросить следующим образом:

officeLocations {
    post_title
    locationInformation {
        city
        streetAddress
    }
}

Это приводит к базовым SQL-запросам формы

SELECT
`meta_id`, `post_id`, `meta_key`, `meta_value`
FROM `wp_postmeta` AS `wp_postmeta`
WHERE `wp_postmeta`.`meta_key` = 'street_address'
AND `wp_postmeta`.`post_id` = 176
LIMIT 1;

а также

SELECT
`id`, `post_author`, `post_title`, `post_content`,
`post_excerpt`, `post_status`, `post_type`, `post_name`,
`post_date`, `post_parent`, `menu_order`, `guid`
FROM `wp_posts` AS `wp_posts`
WHERE (`wp_posts`.`id` = 176 OR `wp_posts`.`post_name` = NULL)
AND `wp_posts`.`post_status` = 'publish'
LIMIT 1;

которые извлекают расширенную настраиваемую информацию о публикациях из таблицы wp_postmeta, сначала просматривая таблицу wp_posts.

Использование этого инструмента генерации схемы на целевой странице скромного веб-сайта приводит к 4035 отдельным SQL-запросам к базе данных. Я не уверен, что это необычно, но это приводит к медленному времени выполнения (~ 4 с на моем MacBook Pro 2015 года).

Я хочу повысить эффективность этих запросов graphql для веб-сайта, данные которого редко меняются (по сути, статический веб-сайт). Исходя из исследований, мои четыре основных направления:

  1. Пакетные запросы с использованием загрузчика данных Facebook. Я почерпнул из этого источника и заглянул в возможности пакетной обработки загрузчика данных для SQL, что может быть сложно пакетировать запросы SQL, сгенерированные наивным резолверы graphql.
  2. Создавайте менее наивные преобразователи графов, используя что-то вроде join-monster
  3. Реализуйте кеширование ключей / значений с помощью Redis или Memcached, которое устанавливает уровень ответа кеш перед сервером GraphQL
  4. Скомпилируйте веб-сайт с динамическими запросами graphql в чисто статический веб-сайт, который затем развертывается как статический веб-сайт (удаляя graphql из уравнения)

Меня интересуют относительные достоинства этих проспектов так же, как и любых других.


person jsindos    schedule 22.07.2018    source источник
comment
Я имею в виду, вы упомянули здесь много вещей, и я не знаю, в чем именно заключается вопрос. Использование таких методов, как загрузчик данных, должно иметь логарифмический эффект на количество отправленных запросов. Проблема, с которой вы столкнулись, по-видимому, связана с тем, что автоматически генерируемые файлы и производительность - это две вещи, объединение которых требует больших усилий. На самом деле есть несколько компаний, которые пытаются решить эту проблему, например Prisma или Hasura.   -  person Herku    schedule 22.07.2018
comment
Полагаю, у меня нет четкого вопроса, однако меня интересуют относительные достоинства различных решений проблемы. Кажется, что загрузчик данных представляет собой «более сложную» проблему для разработки, чем простое кэширование результатов на уровне запроса, однако он не подвергается риску резкого увеличения использования кеша. Я думаю, что для моего конкретного случая использования, поскольку данные по существу статичны, а запросы неизменны, я буду кэшировать на уровне запроса. Я сообщу о своих результатах после внедрения.   -  person jsindos    schedule 23.07.2018
comment
Почему бы не использовать плагин wp-graphql? Клиент Apollo может быть лучше в (нормализованном) кешировании запросов, пакетной обработке и т. Д.   -  person xadm    schedule 03.08.2018


Ответы (1)


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

Запрос 1 (постмета-проблема)

Стандартный wp_postmeta имеет неэффективную схему. Это лучше:

CREATE TABLE wp_postmeta (
    post_id BIGINT UNSIGNED NOT NULL,
    meta_key VARCHAR(255) NOT NULL,
    meta_value LONGTEXT NOT NULL,
    PRIMARY KEY(post_id, meta_key),
    INDEX(meta_key)
    ) ENGINE=InnoDB;

См. здесь для объяснения, что делать, если у вас 767 проблем, и как справиться с требованием для meta_id (которое в основном бесполезно).

Эти советы помогут ускорить выполнение большинства запросов, связанных с wp_postmeta.

Запрос 2 (неправильная формулировка)

  • wp_posts.post_name = NULL всегда терпит неудачу; вместо этого скажите wp_posts.post_name IS NULL.
  • Без ORDER BY LIMIT доставит произвольную строку.
  • OR плохо оптимизируется ...

Перепишем так:

SELECT * FROM 
    ( ( SELECT ...
            FROM `wp_posts` AS `wp_posts`
            WHERE `wp_posts`.`id` = 176
              AND `wp_posts`.`post_status` = 'publish'
            LIMIT 1 )
      UNION DISTINCT
      ( SELECT ...
            FROM `wp_posts` AS `wp_posts`
            WHERE `wp_posts`.`post_name` IS NULL
              AND `wp_posts`.`post_status` = 'publish'
            LIMIT 1 )
    ) LIMIT 1

И тогда это было бы полезно:

INDEX(post_status, post_id)
INDEX(post_status, post_name)

Если вы добавите ORDER BY, его нужно будет добавить в 3 местах; непосредственно перед каждым LIMIT.

Раньше: полное сканирование таблицы wp_posts. В соответствии с моими предложениями: две очень эффективных однорядных выборки плюс определение того, какая из двух строк действительно доставляет.

person Rick James    schedule 23.07.2018
comment
Кэширование на уровне ответа значительно ускоряет работу, но это не универсальное решение. Я хотел бы разработать что-то на уровне DB или ORM, так что это отличное начало. Я также имею дело с неэффективностью, связанной с обходом двойной таблицы для доступа к категориям WordPress, а также с обработкой ORM для доступа к полям повторителя ACF, как описано здесь. - person jsindos; 24.07.2018