대량으로 wp_insert_post 및 add_post_meta에 대한 빠른 방법


16

~ 1,500 행과 97 열로 구성된 삽입하려는 csv 파일이 있습니다. 전체 가져 오기를 수행하는 데 약 2 ~ 3 시간이 걸리며, 방법이있는 경우이를 개선하고 싶습니다. 현재 각 행에 대해 $ post_id = wp_insert_post를 수행 한 다음 각 행과 관련된 97 개의 열에 대해 add_post_meta를 수행하고 있습니다. 이것은 매우 비효율적입니다 ...

post_id가 post와 post_meta 값 사이의 관계를 유지할 수있는 방법 으로이 문제를 해결하는 더 좋은 방법이 있습니까?

지금은 로컬 컴퓨터에서 wamp로 시도하고 있지만 VPS에서 실행 중입니다.


아래의 WP 팁 외에도이 답변에 따라 MySQL에서 InnoDB를 사용하고 트랜잭션을 일괄 커밋하는 방법을 살펴보십시오 .
webaware

답변:


21

언젠가는 맞춤 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()많으면 사용 가능한 슬러그를 찾기 위해 루프 쿼리 반복으로 인해 속도가 느려질 수 있습니다. 이로 인해 많은 수의 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
);

하나 개의 시도는 예 경우 $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 개의 게시물 또는 페이지 만들기 에 대한 답변이 게시되어 있습니까?를 참조하십시오.

그런 다음 import.phpWP-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 .


6
또한 쿼리 기능을 사용하여 자동 커밋을 해제 한 다음 삽입이 완료된 후 수동 커밋을 수행 할 수도 있습니다. 이렇게하면 대량 삽입 작업을 수행 할 때 DB 수준에서 작업 속도가 크게 향상됩니다. SET autocommit=0;인서트 앞에 a 를 보내고 그 뒤에 나옵니다 COMMIT;.
Otto

흥미 롭습니다. 고마워요! 집에 도착하면 테스트해야합니다.
Corey Rowell

@ 오토, 좋은 팁 주셔서 감사합니다. 따라서 $wpdb->query('SET autocommit = 0;');인서트 전에 할 수 있지만 $wpdb->query('START TRANSACTION;');이 경우 건너 뛸 수 있습니까? ;-) 응원에 대해 더 배우려면 MySQL 매뉴얼을 확인하십시오.
birgire

1
좋은 지적이야 이것들이 단지 삽입이고 업데이트 wp_suspend_cache_addition( true )가 아닌 경우, 객체 캐시에 물건을 넣지 않도록 도와야합니다. 또한 @birgire는 MyISAM으로 이것을 테스트하지 않았다고 언급했습니다. 걱정하지 마십시오. 스토리지 엔진은 트랜잭션을 지원하지 않으므로 자동 커밋을 설정하거나 트랜잭션을 시작하면 효과가 없습니다.
kovshenin

1
좋은 팁 @ 오토. 내 쿼리는 이전에 38 초가 걸렸으며 이제는 1 초가 걸립니다.
Annapurna

5

ID를 얻으려면 게시물을 삽입해야하지만 $wpdb->postmeta테이블 구조는 매우 간단합니다. MySQL 문서에서 다음과 같은 간단한 INSERT INTO문장을 사용할 수 있습니다 .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

1
이것은 mysql injection이 발생하는 방식이므로 사용하지 마십시오.
OneOfOne

@OneOfOne이라는 모든 것이 하드 코딩되었습니다. 주입은 사용자가 입력하지 않으면 정의 상으로는 불가능합니다. 이것이 "주입"의 본질입니다. OP는 자신이 제어하는 ​​코드를 사용하여 자신이 제어하는 ​​.csv 파일에서 데이터를 가져오고 있습니다. 제 3자가 어떤 것도 주사 할 가능성은 없습니다. 상황에주의하십시오.
s_ha_dum

+1, 20 개의 사용자 정의 필드 값을 추가해야했으며 이는 "add_post_meta"보다 훨씬 빠릅니다.
Zorox

1
OP가 CSV 파일을 가져 오기 전에 철저하게 검사 할 것으로 기대할 수 없으므로 사용자 입력 및 최소한 ->prepare()SQL 문 으로 처리해야 합니다. 시나리오에서 CSV의 ID 열에 1, 'foo', 'bar'); DROP TABLE wp_users; --?가 포함되어 있으면 어떻게됩니까? 아마도 뭔가 나쁜 것 같습니다.
kovshenin

5

나는 이것을 추가해야했다 :

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

do_all_pings이는 핑백, 인클로저, 트랙백 및 기타 핑을 처리하는 을 건너 뜁니다 (링크 : https://developer.wordpress.org/reference/functions/do_all_pings/ ). 코드를 보면 내 이해는이 remove_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 );

1

에 대한 중요 사항 'SET autocommit = 0;'

설정 한 후 autocommit = 0스크립트가 (어떤 이유로, 같은 대한 실행을 중지하는 경우 exit, 다음 변경이 습관 SAVED IN DB, 치명적인 오류 또는 등 ...)!

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

update_option("something", "value");     

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

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

이 경우 update_optionDB에 저장되지 않습니다!

따라서 최선의 조언은 기능에 사전 분류로 COMMIT등록 shutdown하는 것입니다 (예상치 못한 종료가 발생할 경우).

register_shutdown_function( function(){
    $GLOBALS['wpdb']->query( 'COMMIT;' );
} );
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.