mysql - 如何提高静态网站的 WordPress GraphQL 服务器的效率
问题描述
我最近构建了一个 graphql 模式生成工具,它检查一组 WordPress 高级自定义字段的 JSON 表示以生成一个 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 查询。我不确定这是否不同寻常,但它会导致执行时间变慢(在我的 2015 MacBook Pro 上约为 4 秒)。
我希望为数据很少更改的网站(本质上是静态网站)提高这些 graphql 查询的效率。从研究我的四个主要途径是
- 使用Facebook 的 dataloader进行批量查询。我从这个来源收集并研究了 SQL 的数据加载器的批处理功能,它可能很难批处理由天真的 graphql 解析器生成的 SQL 查询。
- 使用join-monster之类的东西创建不那么简单的 graphql 解析器
- 使用 Redis 或 Memcached 实现键/值缓存,将响应级缓存放在 GraphQL 服务器前面
- 将带有动态 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;
看这里的解释,如果你有 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
. 在我的建议之后:两个非常有效的单行提取,以及确定 2 行中的哪一行确实交付了。
推荐阅读
- python - 如何让 python 应用程序在主机上 24/7 全天候运行?
- python - 将大整数键均匀分布到 N 个桶中
- c++ - 不能在 VS19 中从 'const char*' 转换为 'char*',虽然之前可以
- python - 更改某个角色的频道权限 discord.py
- php - 当前路由的 Laravel 8 前缀
- udp - 使用 netcat 在 localhost 中看不到 tcpreplay 流量
- javascript - 如何通过 onclick 切换开关打开/关闭特定的 JavaScript 脚本?
- html - 为什么我的代码中没有实现 CSS 的特殊性?
- android - 使用子唯一 ID 插入 Firebase 数据
- unity3d - 统一传递精神后如何触发脚本