Mam plik csv, który chcę wstawić, który składa się z ~ 1500 wierszy i 97 kolumn. Pełny import zajmuje około 2-3 godzin i chciałbym to poprawić, jeśli istnieje sposób. Obecnie dla każdego wiersza wykonuję $ post_id = wp_insert_post, a następnie add_post_meta dla 97 powiązanych kolumn z każdym rzędem. To jest dość nieefektywne ...
Czy istnieje lepszy sposób, aby to zrobić w taki sposób, aby post_id mógł zachować związek między wartością post a jej wartościami post_meta?
W tej chwili próbuję tego na moim komputerze lokalnym z wamp, ale będzie działał na VPS
wp-insert-post
Corey Rowell
źródło
źródło
Odpowiedzi:
Miałem kiedyś podobne problemy z niestandardowym importem CSV, ale skończyło się na użyciu niestandardowego kodu SQL dla wstawiania zbiorczego. Ale do tej pory nie widziałem tej odpowiedzi:
Zoptymalizować wstawianie i usuwanie wpisów dla operacji masowych?
używać,
wp_defer_term_counting()
aby włączyć lub wyłączyć liczenie terminów.Ponadto, jeśli sprawdzisz źródło wtyczki importera WordPress, zobaczysz te funkcje tuż przed importem zbiorczym:
a następnie po wkładce zbiorczej:
To może być coś do wypróbowania ;-)
Importowanie postów w wersji roboczej zamiast publikowania również przyspieszy, ponieważ powolny proces znajdowania unikalnego ślimaka dla każdego z nich jest pomijany. Można np. Opublikować je później w mniejszych krokach, ale należy pamiętać, że tego rodzaju podejście musiałoby w jakiś sposób oznaczać zaimportowane posty, więc nie publikujemy żadnych wersji roboczych później! Wymagałoby to starannego planowania i prawdopodobnie niestandardowego kodowania.
Jeśli istnieje np. Wiele podobnych tytułów postów (takich samych
post_name
) do zaimportowania,wp_unique_post_slug()
może stać się powolny z powodu iteracji zapytania pętli w celu znalezienia dostępnego ślimaka. Może to generować ogromną liczbę zapytań db.Od WordPress 5.1
pre_wp_unique_post_slug
filtr jest dostępny, aby uniknąć iteracji pętli dla ślimaka. Zobacz bilet podstawowy nr 21112 . Oto przykład:Jeśli spróbujemy np.
$override_slug = _truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix"
Z$suffix
as$post_id
, to zauważymy, że$post_id
zawsze0
dotyczy to nowych postów, zgodnie z oczekiwaniami. Istnieją różne sposoby generowania unikalnych liczb w PHP, na przykładuniqid( '', true )
. Ale używaj tego filtra ostrożnie, aby upewnić się, że masz unikalne ślimaki. Możemy na przykład uruchomić zapytanie dotyczące liczby grup,post_name
aby się upewnić.Inną opcją byłoby użycie WP-CLI, aby uniknąć przekroczenia limitu czasu. Zobacz np. Moją odpowiedź opublikowaną na temat tworzenia 20 000 postów lub stron przy użyciu pliku .csv?
Następnie możemy uruchomić nasz niestandardowy skrypt importu PHP
import.php
za pomocą komendy WP-CLI:Unikaj także importowania dużej liczby hierarchicznych typów postów, ponieważ bieżący interfejs użytkownika wp-admin nie radzi sobie z tym dobrze. Zobacz np. Niestandardowy typ postu - lista postów - biały ekran śmierci
Oto świetna wskazówka od @otto:
Przed wstawieniem zbiorczym wyłącz
autocommit
tryb jawnie:Po wstawieniu luzem uruchom:
Myślę również, że dobrym pomysłem byłoby wykonanie pewnych czynności porządkowych, takich jak:
Nie testowałem tego na MyISAM, ale to powinno działać na InnoDB .
Jak wspomniano przez @kovshenin, ta wskazówka nie zadziała w MyISAM .
źródło
SET autocommit=0;
przed wkładkami, a następnieCOMMIT;
po.$wpdb->query('SET autocommit = 0;');
przed wstawkami, ale czy możemy$wpdb->query('START TRANSACTION;');
w takim przypadku pominąć ? Sprawdzę instrukcję MySQL, aby dowiedzieć się więcej na ten temat ;-) na zdrowie.wp_suspend_cache_addition( true )
NIE powinno to pomagać w umieszczaniu elementów w pamięci podręcznej obiektów. @ Birgire wspomniał również, że nie testowali tego z MyISAM - nie przejmuj się, silnik pamięci nie obsługuje transakcji, więc ustawienie automatycznego zatwierdzania lub rozpoczęcie transakcji będzie miało zerowy efekt.Będziesz musiał wstawić post, aby uzyskać swój identyfikator, ale
$wpdb->postmeta
tabela jest bardzo prosta w strukturze. Prawdopodobnie możesz użyć prostejINSERT INTO
instrukcji, takiej jak ta z dokumentów MySQL:INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);
W Twoim przypadku...
To nie poradzi sobie z żadnym kodowaniem, serializacją, ucieczką, sprawdzaniem błędów, duplikacjami ani czymkolwiek innym, ale spodziewałbym się, że będzie szybszy (chociaż nie próbowałem).
Nie zrobiłbym tego na miejscu produkcji bez dokładnych testów, a gdybym musiał to zrobić tylko raz lub dwa razy, skorzystałbym z podstawowych funkcji i wziąłbym długi lunch podczas importowania rzeczy.
źródło
->prepare()
instrukcje SQL. W twoim scenariuszu, co by się stało, gdyby kolumna identyfikatora w pliku CSV zawierała coś takiego1, 'foo', 'bar'); DROP TABLE wp_users; --
? Prawdopodobnie coś złego.Musiałem dodać to:
Pamiętaj, że spowoduje to pominięcie
do_all_pings
, które przetwarza pingbacki, załączniki, trackbacki i inne pingi (link: https://developer.wordpress.org/reference/functions/do_all_pings/ ). Rozumiem po spojrzeniu na kod, że oczekujące pingbacki / trackbacki / obudowy będą nadal przetwarzane po usunięciu tegoremove_action
wiersza, ale nie jestem całkowicie pewien.Aktualizacja: Dodałem również
Poza tym używam:
źródło
Ważna uwaga na temat
'SET autocommit = 0;'
po ustawieniu,
autocommit = 0
czy skrypt przestaje działać (z jakiegoś powodu, na przykładexit
błąd krytyczny itp.), to zmiany NIE ZOSTANĄ ZAPISANE W DB!W tym przypadku
update_option
nie zostaną zapisane w DB!Dlatego najlepiej jest
COMMIT
zarejestrować się wshutdown
funkcji jako warunek wstępny (na wypadek nieoczekiwanego wyjścia).źródło