问题描述
我正在为一家公司工作,该公司将很有可能通过自定义职位类型创建数百万个职位。他们是祷告,所以基本上前端的用户只需通过表单提交一个短语。所有公司都关心的是发布内容和发布日期。该网站还没有启动,他们已经有超过 12 万个职位,所以当我说数百万的时候,我死了严重。
所以,几个优化问题:
-
假设我有一个自定义帖子类型中有一个类别’featured’,其中有 50 万个帖子。特色类别只有 500 个帖子。如果我为特色帖子创建了一个查询,我查询了整个 50 万个帖子,还是仅查看了 500 个帖子?如果我只想显示十个最近发布的帖子怎么办?
-
将此自定义帖子类型保存到数据库时,有什么事情可以减少服务器资源,特别是因为唯一真正需要的是帖子和日期的内容?
-
我是否应该使用自定义帖子类型?我原则上喜欢它,因为它很好地集成到 WordPress 管理员中,但是如果性能有很大的缺点,那么我想我可以做不同的事情。
我从来没有在这个规模的项目上工作,所以我比平时更关心性能。感谢任何帮助!
最佳解决方案
1. WP_Query 运行前设置查询
当尝试将数据库查询保持在最小值时,这似乎是最重要的事情,因为修改查询的唯一机会当然是在 SQL 数据库中运行之前。
正常查询对于正常查询,WordPress 使用 wp()
函数,后者又调用 $wp->main( $query_vars )
。来自条件标签的 「is_变量」 在将它们传递给 WP_Query->get_posts()
之前设置,它将其转换成 MySQL 数据库查询,最后将它们存储在 $ wp_query 对象中。在 SQL database 中实际运行查询之前,可以过滤查询。
pre_get_posts
操作挂接到此过程中,允许您将查询更改为传递给 WP_Query->get_posts()
之前。
例如,如果要过滤”featured” 类别中的帖子的查询,您将使用 add_action( 'pre_get_posts', 'your_function_name' );
并在 your_function_name
中包含 in_category
条件标签。
function your_function_name( $query ) {
if ( $query->in_category( 'featured' ) && $query->is_main_query() ) {
// Replace 123 with the category ID of the featured category.
$query->set( 'cat', '123' );
}
}
add_action( 'pre_get_posts', 'your_function_name' );
见 Plugin API/Action Reference/pre get posts « WordPress Codex
页面请求对于页面模板,例如”featured” 类别的归档页面,条件标签将无法从 pre_get_posts
过滤器工作。例如,由于 WP_Query 尚未运行,因此无法使用 is_category
来检查存档页面。
相反,您必须使用 new WP_Query
更改页面请求的主要查询,如 $query = new WP_Query( 'cat=123' );
。这将从开始运行具有适当参数的查询。
见 Class Reference/WP Query « WordPress Codex
2. 保存到数据库
您可以使用过滤器 wp_insert_post_data
确保仅将与您的自定义职位类型相关的 $数据返回给 wp_insert_post
。确保包含条件语句以检查您的自定义帖子类型。 Plugin API/Filter Reference/wp insert post data « WordPress Codex
此钩子由 wp_insert_post
函数调用,当您更新自定义帖子类型时,通常通过保存草稿或发布帖子,wp_update_post 调用该函数。
您必须自己进行基准测试,因为我无法亲自说出减少数据库中更新的数据的优化意义。
自定义帖子类型会影响性能吗?
根据我的经验,自定义帖子类型是管理内容的强大工具。我不知道有什么其他方式来管理发布的所有方式,它允许使用较少的资源。我个人会专注于尽可能减少查询次数的方法。
以前是一个与永久链接结构相关的性能问题,导致它以文本而不是数字开始时受到打击。 3 对于托管大量页面的网站来说,这是特别麻烦的,但是自 WordPress 版本 3.3 起已经解决了。
我只是在这里提出了永久链接,因为 lug is 通常是固定链接结构的第一部分,可能或可能不会影响版本 3.3 之前的性能。除此之外,我不知道使用自定义帖子类型引起的任何性能问题。
其他性能选项
瞬态这不是替代您的代码中的最低限度的查询,但您可以使用 set_transient 存储查询一段时间,以便不需要新的查询。以下是 Dave Clements’ post 中使用的示例。此外,请注意,他建议在每次更新给定的帖子类型时,添加一个 save_post
操作来删除该暂态。
<?php // IN THE SPOTLIGHT QUERY
if( false === ( $its_query = get_transient( 'its_query' ) ) ) {
$pttimestamp = time() + get_option('gmt_offset') * 60*60;
$its_query = new WP_Query( array(
'post_type' => 'spotlight',
'posts_per_page' => 1,
'post__not_in' => $do_not_duplicate,
'meta_query' => array(
array(
'key' => '_hpc_spotlight_end_time',
'value' => $pttimestamp,
'compare' => '>'
)
)
) );
set_transient( 'its_query', $its_query, 60*60*4 );
}
if( have_posts() ) { // HIDE SECTION IF NO CURRENT ITS FEATURE ?>
// LOOP GOES HERE: NOT IMPORTANT TO EXAMPLE
<?php } ?>
更多查询优化 Thomas Griffin 在他的 Optimize WordPress Queries 教程中有几个很好的提示。以下是他的建议的简要列表:
-
设置’cache_results’ => 如果您的服务器不使用持久性缓存 (如 Memcached),则在 one-off 中查询是否为 false 。 One-off 查询被描述为 「用于显示少量数据的查询,可能是您只想显示与当前帖子相关的链接的帖子,或者您可能需要显示一个下拉列表以选择特定的选项设置 「。他的例子:$ query = get_posts(array(‘posts_per_page’ => 1,’cache_results’ => false));
-
设置’no_found_rows’ => 真的不需要分页。这将 「绕过 MySQL 计算结果,看看我们是否需要分页。」 他的例子:$ query = new WP_Query(array(‘posts_per_page’ => 1,’no_found_rows’ => true));
-
只有在
get_posts
中需要'fields' => 'ids'
的情况下才能查询帖子 ID 。这应该显著减少返回的数据量,如果你看看 Database Description « WordPress Codex 他的例子,这是相当多的:$query = get_posts( array( 'posts_per_page' => 1,
'fields' => 'ids' ) );
除了最后一个提示,当您只需要使用 get_post_field 只需要一个或几个后期字段时,也可以应用相同的推理。
了解查询的工作原理是非常重要的。您的查询越具体,您从 SQL 数据库中要求的工作越少。这意味着管理数据库查询的可能性很大。使用自定义查询,直到它们运行的位置 (是管理页面吗?),在直接查询中使用正确的 sanitization,并尝试使用本机 WordPress 功能,让您能够实现相同的性能。
参考文献
注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。