是否有更好的方法来解决这个问题,即可以获取post_id来保持post及其post_meta值之间的关系?
现在,我正在使用wamp的本地计算机上尝试此操作,但将使其在VPS上运行
#1 楼
某个时候,我在使用自定义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 );
所以这可能是要尝试的东西;-)
将帖子作为草稿而不是发布导入,也会加快速度向上,因为跳过了为每个人寻找唯一子弹的缓慢过程。一个可以例如稍后以较小的步骤发布它们,但是请注意,这种方法需要以某种方式标记导入的帖子,因此我们不只是稍后发布任何草稿!
如果有例如要导入很多类似的帖子标题(相同的
post_name
),则由于循环查询迭代查找可用的子弹,wp_unique_post_slug()
可能变慢。这可能会生成大量的数据库查询。自WordPress 5.1起,可以使用
pre_wp_unique_post_slug
过滤器来避免对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以避免超时。参见例如我的答案发布为使用.csv文件创建20,000个帖子或页面?
然后,我们可以使用WP-CLI命令运行自定义PHP导入脚本
import.php
:wp eval-file import.php
也避免像当前的wp-admin那样导入大量的分层文章类型用户界面处理不好。参见例如自定义帖子类型-帖子列表-死亡白屏
这里是@otto的提示:
在批量插入之前,请明确禁用
autocommit
模式:$wpdb->query( 'SET autocommit = 0;' );
大容量插入后,运行:
$wpdb->query( 'COMMIT;' );
我也认为做一些整理工作是个好主意,例如:
$wpdb->query( 'SET autocommit = 1;' );
我没有在MyISAM上测试过,但这应该在InnoDB上有效。
@kovshenin提到的这一技巧不会为MyISAM工作。
评论
除此之外,还可以使用查询功能在插入之前关闭自动提交,然后在插入之后手动提交。进行批量插入时,这可以大大加快数据库级别的操作。只需发送SET autocommit = 0;在插入之前,后面是COMMIT;之后。
–奥托
13年6月8日在20:27
有趣,谢谢!我到家时必须测试一下。
– Corey Rowell
13年6月8日在20:31
@Otto,感谢您的宝贵建议。因此我们可以执行$ wpdb-> query('SET autocommit = 0;');在插入之前,但是我们可以跳过$ wpdb-> query('START TRANSACTION;');吗?在这种情况下?我将查看MySQL手册以进一步了解它;-)欢呼。
–birgire
2013年6月8日在21:05
好点马克。如果这些只是插入而不是更新,则wp_suspend_cache_addition(true)应该有助于将内容不放入对象缓存中。 @birgire还提到他们没有使用MyISAM对此进行测试-不用担心,存储引擎不支持事务,因此设置自动提交或开始事务将产生零影响。
–kovshenin
16年8月2日,0:01
大提示@Otto。我的查询之前花费了38秒,现在花费了1秒。
–安纳布尔纳
17年8月22日在10:47
#2 楼
我必须添加此代码: 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 );
#3 楼
您将需要插入帖子以获取您的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}");
不会处理任何编码,序列化,转义,错误检查,重复或其他操作,但是我希望它会更快(尽管我没有尝试过)。
我不会做无需经过全面测试就可以在生产现场进行此操作,如果只需要执行一次或两次,则可以使用核心功能并在导入内容时花很长的午餐。
评论
认为我会吃一顿长饭,而不是将原始数据插入表中,并且没有必要重写Wordpress已经完成的工作。
– Corey Rowell
2013年6月8日18:27
这就是mysql注入的过程,所以请不要使用它。
–OneOfOne
15年3月9日在17:04
一切都是硬编码的@OneOfOne。没有用户提供的输入,注入就不会发生-根据定义是不会发生的。这就是“注射”的性质。 OP正在使用他控制下的代码从.csv文件中导入数据,该文件由他控制。第三方注入任何东西都是没有机会的。请注意上下文。
– s_ha_dum
2015年4月10日0:00,
从我+1,我需要添加20个海关字段值,这比“ add_post_meta”要快得多
–佐罗克斯
2015年10月5日12:48
您不能指望OP在导入之前彻底检查CSV文件,因此您应该将其视为用户输入,并且至少-> prepare()SQL语句。在您的方案中,如果CSV中的ID列包含诸如1,'foo','bar')之类的内容,将会发生什么?删除表wp_users; -?可能是坏事。
–kovshenin
16年8月1日在23:58
#4 楼
关于'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
不会保存在数据库中!因此,最好的建议是在
COMMIT
函数中注册shutdown
作为预警(以防万一发生意外退出)。register_shutdown_function( function(){ $GLOBALS['wpdb']->query( 'COMMIT;' ); } );
评论
除了下面的WP技巧,还请按照此答案查看在MySQL中使用InnoDB并批量提交事务。