Answers:
以前,我在使用自定义CSV导入时遇到了类似的问题,但是最后我通过对批量插入使用一些自定义SQL来结束。但那时我还没有看到这个答案:
用于wp_defer_term_counting()
启用或禁用术语计数。
另外,如果您查看WordPress导入程序插件的源代码,则将在批量导入之前看到以下功能:
wp_defer_term_counting( true );
wp_defer_comment_counting( true );
然后在批量插入之后:
wp_defer_term_counting( false );
wp_defer_comment_counting( false );
所以这可能是要尝试的东西;-)
将帖子作为草稿而不是publish导入也可以加快速度,因为跳过了为每个帖子查找唯一的条目的缓慢过程。例如,可以稍后以较小的步骤发布它们,但是请注意,这种方法将需要以某种方式标记导入的帖子,因此我们不只是稍后再发布任何草稿!这将需要仔细计划,并且很可能需要一些自定义编码。
例如,如果post_name
要导入很多相似的帖子标题(相同),则wp_unique_post_slug()
可能会由于循环查询迭代以查找可用的条目而变慢。这可能会生成大量的数据库查询。
从WordPress 5.1开始,该pre_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
as作为示例$post_id
,那么我们会注意到,这$post_id
总是0
如预期的那样适用于新帖子。尽管有多种方法可以在PHP中生成唯一数字,例如uniqid( '', true )
。但是请小心使用此过滤器,以确保您有独特的子弹。我们可以例如稍后运行组计数查询post_name
来确保。
另一种选择是使用WP-CLI以避免超时。请参阅例如我发布的关于使用.csv文件创建20,000个帖子或页面的答案?
然后,我们可以import.php
使用WP-CLI命令运行自定义PHP导入脚本:
wp eval-file import.php
还应避免导入大量的分层帖子类型,因为当前的wp-admin UI不能很好地处理它。参见例如自定义帖子类型-帖子列表-死亡白屏
这是@otto的妙招:
在批量插入之前,请autocommit
明确禁用该模式:
$wpdb->query( 'SET autocommit = 0;' );
批量插入后,运行:
$wpdb->query( 'COMMIT;' );
我也认为做一些整理工作是个好主意,例如:
$wpdb->query( 'SET autocommit = 1;' );
我没有在MyISAM上测试过,但这应该在InnoDB上有效。
正如@kovshenin 所提到的,该技巧不适用于MyISAM。
SET autocommit=0;
在插入之前发送一个,然后再发送一个COMMIT;
。
$wpdb->query('SET autocommit = 0;');
在插入之前进行操作,但是$wpdb->query('START TRANSACTION;');
在这种情况下可以跳过吗?我将查看MySQL手册以进一步了解它;-)欢呼。
wp_suspend_cache_addition( true )
则应帮助不要将内容放入对象缓存中。@birgire还提到他们没有使用MyISAM对此进行测试-不用担心,存储引擎不支持事务,因此设置自动提交或开始事务将产生零影响。
您将需要插入帖子以获取您的ID,但是$wpdb->postmeta
表格的结构非常简单。您可能使用直接的INSERT INTO
语句,例如来自MySQL文档的语句: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}");
这不会处理任何编码,序列化,转义,错误检查,重复或其他任何操作,但是我希望它会更快(尽管我没有尝试过)。
未经全面测试,我不会在生产现场执行此操作,如果只需要执行一次或两次,我将使用核心功能并在导入内容时花很长时间。
->prepare()
SQL语句。在您的方案中,如果CSV中的ID列包含类似的内容,会发生什么1, 'foo', 'bar'); DROP TABLE wp_users; --
?可能是坏事。
我必须添加以下内容:
remove_action('do_pings', 'do_all_pings', 10, 1);
请记住,这将跳过do_all_pings
,它会处理pingback,附件,引用和其他ping(链接:https : //developer.wordpress.org/reference/functions/do_all_pings/)。通过查看代码,我的理解是,删除此remove_action
行后,仍将处理未决的pingbacks / trackbacks /机箱,但是我不确定。
更新:我还添加了
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 );
'SET autocommit = 0;'
设置autocommit = 0
脚本是否停止执行(由于某种原因,例如exit
致命错误等)后,您所做的更改就不会保存在数据库中!
$wpdb->query( 'SET autocommit = 0;' );
update_option("something", "value");
exit; //lets say, here happens error or anything...
$wpdb->query( 'COMMIT;' );
在这种情况下,update_option
将不会保存在数据库中!
因此,最好的建议是先COMMIT
注册shutdown
功能(以防万一发生意外退出)。
register_shutdown_function( function(){
$GLOBALS['wpdb']->query( 'COMMIT;' );
} );