提高插件操作的性能

时间:2015-11-19 作者:Iurie

我想用新操作覆盖第三方插件操作,但在注释中my another question @PieterGoosen建议,就使用服务器资源而言,这个插件操作非常昂贵。所以,我的问题是how to improve this plugin action to make it less expensive?

我认为唯一能改进这个插件操作的是添加一个新的查询参数-\'fields\' => \'ids\', 这将提高其性能。Are here other things to do for this?

add_action( \'adverts_event_expire_ads\', \'adverts_event_expire_ads\' );

/**
 * Expires ads
 * 
 * Function finds Adverts that already expired (value in _expiration_date
 * meta field is lower then current timestamp) and changes their status to \'expired\'.
 * 
 * @since 0.1
 * @return void
 */
function adverts_event_expire_ads() {

    // find adverts with status \'publish\' which exceeded expiration date
    // (_expiration_date is a timestamp)
    $posts = new WP_Query( array(
        "fields" => "ids", //added for performance
        "post_type" => "advert",
        "post_status" => "publish",
        "meta_query" => array(
            array(
                "key" => "_expiration_date",
                "value" => current_time( \'timestamp\' ),
                "compare" => "<="
            )
        )
    ) );


    if( $posts->post_count ) {
        foreach($posts->posts as $post) {
            // change post status to expired.
            $update = wp_update_post( array( 
                "ID" => $post->ID,
                "post_status" => "expired"
            ) );
        } // endforeach
    } // endif

}

UPDATE

我更新了性能(我希望是这样)并改写了代码,所以现在它不仅会让帖子“过期”,而且还会通知帖子作者这一点,并且可以正常工作(经过测试)。但问题是一样的:can it be improved/optimised for performance?

remove_action( \'adverts_event_expire_ads\', \'adverts_event_expire_ads\' );
add_action( \'adverts_event_expire_ads\', \'my_adverts_event_expire_ads\' );

/**
 * Expires ads
 * 
 * Function finds Adverts that already expired (value in _expiration_date
 * meta field is lower then current timestamp) and changes their status to \'expired\'.
 * 
 * @since 0.1
 * @return void
 */

function my_adverts_event_expire_ads() {
    // Set our query arguments
    $args = [
        \'fields\'      => \'ids\',
        \'post_type\'   => \'advert\',
        \'post_status\' => \'publish\',
        \'meta_query\'  => [
            [
                 \'key\'     => \'_expiration_date\',
                 \'value\'   => current_time( \'timestamp\' ),
                 \'compare\' => \'<=\'
             ]
         ]
    ];

    // get adverts with status \'publish\' which exceeded expiration date
    // (_expiration_date is a timestamp)
    $posts = get_posts( $args );

    // Check if we have adverts with exceeded expiration date, if not, return false
    if ( !$posts )
        return false;

    // If we have posts with exceeded expiration time, lets change their status to expired
    foreach($posts as $id) {
        // change post status to expired.
        $update = wp_update_post( array( 
            "ID" => $id,
            "post_status" => "expired"
        ) );

        // Send an email about expiration to the post author
        $post = get_post($id);
        $author = get_userdata($post->post_author);
        $author_name = get_post_meta( $id, \'adverts_person\', true );
        $message = 
            "Hi " . $author_name . ", " . 
            "\\n\\nYour advert, \\"" . $post->post_title . "\\", expired and will be deleted in 7 days." . 
            "\\n\\nBest regards, \\n\\"" . get_bloginfo() . "\\" team";
        wp_mail($author->user_email, "Your article expired!", $message);

    } // endforeach
}

1 个回复
最合适的回答,由SO网友:Pieter Goosen 整理而成

您的原始代码(上一个问题中的代码)在给定的上下文中确实需要一些性能提升。对于更新的代码,您需要删除fields 参数,因为您需要获取完整的post对象,而不仅仅是ID。

要优化查询中的代码,您需要事先知道您需要从帖子中获得什么。我将用你上面的两个例子来解释。

在此之前,请快速执行以下操作:(这将有助于理解我想说的内容)

创建页面模板,并使用该模板创建新页面并在模板中添加以下行

timer_start();

// We will add our queries here

echo get_num_queries(); . \' queries in \' . timer_stop(1, 5); . \' seconds.\';
加载页面并记录查询量。您需要从计时器之间运行的所有查询中减去此数字

一旦有了基准测试,请分别添加以下两个查询来代替// We will add our queries here并注意运行查询所需的时间差异。(这是测试查询及其效率的好方法)

(1)

$q = get_posts( \'post_type=advert&posts_per_page=-1\' );
var_dump( $q );
()

$q = get_posts( \'post_type=advert&posts_per_page=-1&fields=ids\' );
var_dump( $q );
另请注意,不要使用全局变量($posts$post)作为局部变量,这会打断全局变量并给出意外的输出。这种情况很难调试。使用唯一且不在全局变量范围内的局部变量。唯一必须用作局部变量的全局变量是$post 将postdata设置为setup_postdata( $post ) 期望$post 全球的完成后请记住重置它wp_reset_postdata().

代码块1在第一个代码块的上下文中,查询所需的全部是post IDwp_update_post() 只需要post ID。如果查看源代码,wp_update_post() 进行自己的调用,以获取完整的post对象与传递给它的数组合并。

代码所做的是检索完整的post对象,从中获取ID,并将其传递给wp_update_post() 然后wp_update_post() 再次调用以从ID获取完整的post对象。这既昂贵又不必要,就像两次吃同一块肉一样。

您必须记住,即使帖子被缓存到缓存中,获取相关数据仍然需要时间,而且获取的数据越多,所需时间就越长。这就是\'fields\'=>\'ids\' 很方便,因为它将检索一个post ID数组,而不是post对象数组(请检查我要求您测试的测试数据)。一切正常,只是循环略有不同,因为您的帖子是作为ID而不是对象返回的

代码块一可以是这样的

add_action( \'adverts_event_expire_ads\', \'adverts_event_expire_ads\' );

/**
 * Expires ads
 * 
 * Function finds Adverts that already expired (value in _expiration_date
 * meta field is lower then current timestamp) and changes their status to \'expired\'.
 * 
 * @since 0.1
 * @return void
 */
function adverts_event_expire_ads() {

    // find adverts with status \'publish\' which exceeded expiration date
    // (_expiration_date is a timestamp)
    $q = new WP_Query( array(
        "fields" => "ids", //added for performance
        "post_type" => "advert",
        "post_status" => "publish",
        "meta_query" => array(
            array(
                "key" => "_expiration_date",
                "value" => current_time( \'timestamp\' ),
                "compare" => "<="
            )
        )
    ) );


    if( $q->post_count ) {
        foreach($q->posts as $post_id) {
            // NOTE: $q->posts are an array of post ID\'s, so $post_id is a post ID
            // change post status to expired.
            $update = wp_update_post( array( 
                "ID" => $post_id,
                "post_status" => "expired"
            ) );
        } // endforeach
    } // endif

}
代码块2在上下文中,可以删除\'fields\'=>\'ids\' 在这里两个原因

你需要帖子的作者和标题等信息,而不仅仅是帖子ID。如果你需要帖子ID以外的其他信息,你别无选择,只能获取完整的帖子对象。你可以试试posts_fields 过滤器只返回某些字段,但在测试中,这并没有产生任何明显的差异。另请注意,此筛选器未打开get_posts() 默认情况下

您正在使用get_post() 从post ID获取post数据。如果post在post缓存中,这不会创建额外的db查询,但获取post对象确实需要额外的时间。这一切都是不必要的。最好从一开始就获得完整的post对象

因此,您可以在代码块2中重写函数,如下所示:

remove_action( \'adverts_event_expire_ads\', \'adverts_event_expire_ads\' );
add_action( \'adverts_event_expire_ads\', \'my_adverts_event_expire_ads\' );

/**
 * Expires ads
 * 
 * Function finds Adverts that already expired (value in _expiration_date
 * meta field is lower then current timestamp) and changes their status to \'expired\'.
 * 
 * @since 0.1
 * @return void
 */

function my_adverts_event_expire_ads() {
    // Set our query arguments
    $args = [
        \'post_type\'   => \'advert\',
        \'post_status\' => \'publish\',
        \'meta_query\'  => [
            [
                 \'key\'     => \'_expiration_date\',
                 \'value\'   => current_time( \'timestamp\' ),
                 \'compare\' => \'<=\'
             ]
         ]
    ];

    // get adverts with status \'publish\' which exceeded expiration date
    // (_expiration_date is a timestamp)
    $q = get_posts( $args );

    // Check if we have adverts with exceeded expiration date, if not, return false
    if ( !$q )
        return;

    // If we have posts with exceeded expiration time, lets change their status to expired
    foreach($q as $post_object) {
        // $post_object is now an object of post data
        // change post status to expired.
        $update = wp_update_post( array( 
            "ID" => $post_object->ID,
            "post_status" => "expired"
        ) );

        // Send an email about expiration to the post author
        $author = get_userdata($post_object->post_author);
        $author_name = get_post_meta( $post_object->ID, \'adverts_person\', true );
        $message = 
            "Hi " . $author_name . ", " . 
            "\\n\\nYour advert, \\"" . $post_object->post_title . "\\", expired and will be deleted in 7 days." . 
            "\\n\\nBest regards, \\n\\"" . get_bloginfo() . "\\" team";
        wp_mail($author->user_email, "Your article expired!", $message);

    } // endforeach
}
额外注意事项:正如我所说,在优化查询之前,您需要知道您需要从查询中获得什么。

在使用函数之前,请确保您了解其内部工作原理。例如,get_category_link() 接受类别ID或类别对象作为参数。使用这两个选项中错误的一个会对性能产生巨大影响,特别是如果你有很多类别的话。当您传递ID时,函数将进行db调用,以获取category对象来构建链接。如果传递该对象,则该对象将按原样用于构建链接,因此不会执行db调用。

developer.wordpress.org 是一种查找函数及其源代码的好方法,因此请将此地址添加到书签中并加以滥用

使用cache parameters in WP_Query 如果您不需要缓存术语和自定义字段数据,还可以提高性能,从而实现术语和自定义字段数据的缓存。

使用我给您的小测试脚本来测试查询和自定义代码。这样,您将知道代码将如何执行。另外,下载并安装一个插件,如Query MonitorDebug Objects 在本地测试安装上。这将分解查询,以便您可以检查每个查询,并检查其实际效率。它还有助于调试。我个人认为每个人都应该在他们的测试装置上安装这两个冥王星

相关推荐

Calculations in functions.php

我为自己创建了一个发票主题,并试图在自定义列中获取发票总额。我已经尝试调整模板页面中使用的代码,以便在函数中显示这一点。php文件,但它不工作。我的乘法操作数出现了一个操作数错误,我不知道为什么。这是我的代码(如有任何帮助,将不胜感激)。if( $column_name == \'invoice_total\' ) { $hours = 0; // This allows counting of each sub_field //* Set repeater va