如何为静态网站提高WordPress GraphQL服务器的效率

时间:2018-07-22 05:18:19

标签: mysql sql performance graphql gatsby

recently built一个graphql模式生成工具,该工具检查一组WordPress高级自定义字段的JSON表示以生成graphql模式。 JSON表示基于SQL数据库中存在的自定义帖子类型和高级自定义字段。

例如,使用自定义字段Office Locationcity定义名为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查询。我不确定这是否与众不同,但这会导致执行时间变慢(在我的2015 MacBook Pro上约为4s)。

我正在寻找一种针对数据很少变化的网站(本质上是静态网站)来提高这些graphql查询效率的方法。根据研究,我的四个主要途径是

  1. 使用Facebook's dataloader批量查询。我从this source收集并调查了batching capabilities of dataloader for SQL,发现很难对朴素的graphql解析器生成的SQL查询进行批处理。
  2. 使用类似join-monster的东西来创建少一些朴素的graphql解析器
  3. 使用Redis或Memcached实施键/值缓存,该缓存放置response-level cache in front of the GraphQL server
  4. 将具有动态graphql请求的网站编译为纯静态网站,然后将其部署为静态网站(从等式中删除graphql)

我对这些途径以及其他途径的相对优点感兴趣。

1 个答案:

答案 0 :(得分:2)

在着手进行缓存和其他耗能大的“解决方案”之前,我们先做一些事情来加快查询本身的速度。

查询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;

有关说明,请参见here,遇到问题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的全表扫描。根据我的建议:两次非常高效的单行访存,并确定可以传送两行中的哪一行。