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

标签 mysql sql performance graphql gatsby

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

例如,使用自定义字段 citystreet_address 定义名为 Office Location 的自定义帖子类型会生成一个 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_posts 表,从 wp_postmeta 表中提取高级自定义帖子信息。

在一个普通网站的登陆页面上使用此架构生成工具会导致对数据库进行 4035 个单独的 SQL 查询。我不确定这是否异常,但它会导致执行时间变慢(在我的 2015 MacBook Pro 上约为 4 秒)。

我希望提高数据很少变化的网站(本质上是静态网站)的这些 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(postmeta 问题)

标准的 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 BYLIMIT 将提供任意行。
  • 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进行全表扫描。根据我的建议:两次非常高效的单行获取,再加上确定两行中的哪一行确实交付。

关于mysql - 如何提高静态网站的 WordPress GraphQL 服务器的效率,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51462263/

相关文章:

mysql - GROUP BY 在 MySQL 中使用通配符

java - 寻找具有高效查找和磁盘持久性的字符串键映射

sql - 对索引、主键、唯一键的影响的详细信息

mysql - 使用多列子查询优化查询

mysql - SQL 用户定义函数未运行

php - octobercms 数据库查询缓存不工作

sql - 在 SQL Server 的表中存储带有操作数的运算符

performance - TSQL-设置多个变量的有效方法

java - 如何将系统日期与数据库mysql中的日期相匹配

mysql - 忽略具有日期范围的 SQL 查询中的年份