批量执行wp_插入_POST和添加_POST_META的更快方式

时间:2013-06-08 作者:Corey Rowell

我有一个要插入的csv文件,它由约1500行和97列组成。完全导入大约需要2-3个小时,如果有办法的话,我想对此进行改进。目前,我正在为每一行执行$post\\u id=wp\\u insert\\u post,然后为每一行的97个关联列执行add\\u post\\u meta。这是相当低效的。。。

有没有更好的方法来实现这一点,使a可以获得post\\u id并保持post与其post\\u元值之间的关系?

现在我正在使用wamp在我的本地计算机上尝试此功能,但将在VPS上运行它

4 个回复
最合适的回答,由SO网友:birgire 整理而成

前一段时间,我在自定义CSV导入时遇到了类似的问题,但我最终使用了一些自定义SQL进行批量插入。但那时我还没有看到这个答案:

Optimize post insert and delete for bulk operations?

使用wp_defer_term_counting() 启用或禁用术语计数。

如果您查看source 对于WordPress导入器插件,您将在批量导入之前看到以下功能:

wp_defer_term_counting( true );
wp_defer_comment_counting( true );
然后在批量插入之后:

wp_defer_term_counting( false );
wp_defer_comment_counting( false );
所以这可能是要尝试的;-)

将帖子导入为草稿而不是发布,也会加快速度,因为会跳过为每个帖子找到唯一slug的缓慢过程。例如,可以稍后以较小的步骤发布它们,但请注意,这种方法需要以某种方式标记导入的帖子,所以我们不只是稍后发布任何草稿!这需要仔细规划,很可能需要一些自定义编码。

如果有很多类似的职位名称(相同post_name) 要导入,则wp_unique_post_slug() 由于循环查询迭代以查找可用的段塞,可能会变得很慢。这可能会生成大量的db查询。

自WordPress 5.1pre_wp_unique_post_slug 过滤器可用于避免段塞的循环迭代。参见核心票据#21112. 下面是一个示例:

add_filter( \'pre_wp_unique_post_slug\', 
    function( $override_slug, $slug, $post_id, $post_status, $post_type, $post_parent ) {
        // Set a unique slug value to shortcircuit the slug iteration loop.
        // $override_slug = ...

        return $override_slug;
    }, 10, 6
);
如果有人尝试,例如。$override_slug = _truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix" 具有$suffix$post_id, 然后我们会注意到$post_id 始终是0 对于新职位,如预期的那样。在PHP中有多种方法可以生成唯一的数字,如uniqid( \'\', true ). 但要小心使用这个过滤器,确保你有独特的鼻涕虫。例如,我们可以在上运行组计数查询post_name 当然

另一种选择是使用WP-CLI 以避免超时。参见例如我的答案张贴Creating 20,000 Posts or Pages using a .csv file?

然后我们可以运行定制的PHP导入脚本import.php 使用WP-CLI命令:

wp eval-file import.php
还要避免导入大量层次结构的帖子类型,因为当前的wp admin UI不能很好地处理它。参见示例。Custom post type - posts list - white screen of death

Here\'s the great tip from @otto:

在批量插入之前,请禁用autocommit 模式明确:

$wpdb->query( \'SET autocommit = 0;\' );
批量插入后,运行:

$wpdb->query( \'COMMIT;\' );
我还认为做一些家务活是个好主意,比如:

$wpdb->query( \'SET autocommit = 1;\' );
我没有在MyISAM上测试过这个,但这应该可以在InnoDB上使用。

mentioned 作者@kovshenin这条提示对MyISAM不起作用。

SO网友:firasd

我必须补充一点:

    remove_action(\'do_pings\', \'do_all_pings\', 10, 1);
请记住,这将跳过do_all_pings, 处理pingback、机柜、trackback和其他ping(链接:https://developer.wordpress.org/reference/functions/do_all_pings/). 通过查看代码,我的理解是,在删除此代码后,仍将处理挂起的pingback/trackback/enclosuresremove_action 行,但我不完全确定。

更新:我还添加了

    define( \'WP_IMPORTING\', true );
除此之外,我还使用:

    ini_set("memory_limit",-1);
    set_time_limit(0);
    ignore_user_abort(true);

    wp_defer_term_counting( true );
    wp_defer_comment_counting( true );
    $wpdb->query( \'SET autocommit = 0;\' );

    /* Inserting 100,000 posts at a time
       including assigning a taxonomy term and adding meta keys
       (i.e. a `foreach` loop with each loop containing:
       `wp_insert_post`, `wp_set_object_terms`, `add_post_meta`.)
    */

    $wpdb->query( \'COMMIT;\' );
    wp_defer_term_counting( false );
    wp_defer_comment_counting( false );

SO网友:s_ha_dum

您需要插入帖子以获取您的ID,但$wpdb->postmeta 这张桌子的结构很简单。你可以直接INSERT INTO 陈述like this from the MySQL docs: INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);

就你而言。。。

$ID = 1; // from your wp_insert_post
$values = \'($ID,2,3),($ID,5,6),($ID,8,9)\'; // build from your 97 columns; I\'d use a loop of some kind
$wpdb->query("INSERT INTO {$wpdb->postmeta} (post_id,meta_key,meta_value) VALUES {$values}");
这不会处理任何编码、序列化、转义、错误检查、复制或其他任何事情,但我希望它会更快(尽管我没有尝试)。

如果没有彻底的测试,我不会在生产站点上做这件事,如果我只需要做一两次,我会使用核心功能,在导入东西时吃一顿长午餐。

SO网友:T.Todua

关于的重要说明\'SET autocommit = 0;\'

设置后autocommit = 0 如果脚本停止执行(出于某种原因,如exit, 致命错误等…),那么您的更改将不会保存在DB中!

$wpdb->query( \'SET autocommit = 0;\' );

update_option("something", "value");     

exit; //lets say, here happens error or anything...

$wpdb->query( \'COMMIT;\' );
在这种情况下update_option 不会保存在DB中!

因此,最好的建议是COMMIT 注册于shutdown 起到预防作用(以防发生意外退出)。

register_shutdown_function( function(){     $GLOBALS[\'wpdb\']->query( \'COMMIT;\' );    } );

结束

相关推荐