web-dev-qa-db-ja.com

Wp_insert_postおよびadd_post_metaへの一括一括送信

私は挿入したいcsvファイルを持っています。それは〜1,500行と97列で構成されています。フルインポートを行うのに約2〜3時間かかります。方法がある場合はこれを改善したいと思います。現在、各行に対して$ post_id = wp_insert_postを実行してから、各行に関連付けられた97列に対してadd_post_metaを実行しています。これはかなり非効率的です...

Aがpost_idにpostとそのpost_metaの値の関係を保つことができるような方法でこれについて取り組むより良い方法はありますか?

今、私はwampで私のローカルマシンでこれを試していますが、VPSでそれを走らせるでしょう

13
Corey Rowell

私はカスタムCSVインポートに関しても同様の問題を以前に抱えていましたが、一括挿入にカスタムSQLを使用することになりました。しかし、私はそれまでにこの答えを見ていませんでした:

一括操作の挿入後削除を最適化しますか?

用語のカウントを有効または無効にするには、 wp_defer_term_counting() を使用します。

また、WordPressインポータープラグインの source )をチェックアウトすると、一括インポートの直前にこれらの関数が表示されます。

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()が遅くなる可能性があります。これにより、膨大な数のdbクエリが生成される可能性があります。

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
);

例えば試してみると$suffix$post_idとして$override_slug = _truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix"とすると、期待通り、新しい投稿では$post_idは常に0であることに気付くでしょう。 uniqid( '', true )のように、PHPでユニークな数を生成するにはさまざまな方法があります。しかし、あなたがユニークなナメクジを持っていることを確認するために慎重にこのフィルターを使用してください。例えば後でpost_nameに対してグループカウントクエリを実行してください。

タイムアウトを回避するには WP-CLI を使用します。例えば、 .csvファイルを使用して20,000の投稿またはページを作成しますか? について投稿された回答を参照してください。

それから、WP-CLIコマンドでカスタムPHPインポートスクリプトimport.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ではうまくいきません。

18
birgire

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}");

これは、エンコーディング、シリアライゼーション、エスケープ、エラーチェック、複製、その他には関係ありませんが、もっと速くなることを期待しています(試したことはありませんが)。

私は本番サイトで徹底的なテストなしにこれをしないでしょう、そして私が一度か二度だけそれをしなければならなかったならば、私は物事が輸入する間、私はコア機能を使い、長い昼食をとるでしょう。

5
s_ha_dum

私はこれを追加しなければなりませんでした:

    remove_action('do_pings', 'do_all_pings', 10, 1);

これはdo_all_pingsをスキップすることに注意してください。これはpingback、エンクロージャ、trackback、そして他のpingを処理します(link: https://developer.wordpress.org/reference/functions/do_all_pings/ )。コードを見て私が理解しているのは、このremove_action行を削除しても、保留中のpingback/trackback/enclosuresは処理されるということですが、完全にはわかりません。

更新日:私も追加しました

    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
firasd

'SET autocommit = 0;'に関する重要な注意

スクリプトが実行を停止した場合(何らかの理由でexit、致命的なエラーなど)にautocommit = 0を設定した後は、変更はDBに保存されません。

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

update_option("something", "value");     

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

$wpdb->query( 'COMMIT;' );

この場合update_optionはDBに保存されません!

そのため、万が一のためにCOMMITshutdown関数に登録することをお勧めします(予期しない終了が発生した場合)。

register_shutdown_function( function(){
    $GLOBALS['wpdb']->query( 'COMMIT;' );
} );
0
T.Todua