it-swarm.com.de

Langsame WP_Query für benutzerdefinierten Beitragstyp

Ich habe ein Immobilienmotiv mit benutzerdefiniertem Beitrag: Eigenschaften. Post hat viele Meta-Werte wie Preis und Taxonomie wie Standort. Ich habe eine Suchmaschine dafür erstellt, aber die Ausführung von Abfragen nimmt unglaublich viel Zeit in Anspruch.

Ich habe nur 50 Eigenschaften in der Datenbank, aber die Tabelle wp_postmeta enthält 20044 Zeilen.

Beispielabfrage, die über 30s dauert:

SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
FROM wp_posts
LEFT JOIN wp_term_relationships
ON (wp_posts.ID = wp_term_relationships.object_id)
LEFT JOIN wp_term_relationships AS tt1
ON (wp_posts.ID = tt1.object_id)
INNER JOIN wp_postmeta
ON ( wp_posts.ID = wp_postmeta.post_id )
INNER JOIN wp_postmeta AS mt1
ON ( wp_posts.ID = mt1.post_id )
INNER JOIN wp_postmeta AS mt2
ON ( wp_posts.ID = mt2.post_id )
INNER JOIN wp_postmeta AS mt3
ON ( wp_posts.ID = mt3.post_id )
WHERE 1=1
AND ( wp_term_relationships.term_taxonomy_id IN (6)
AND tt1.term_taxonomy_id IN (19,287) )
AND ( wp_postmeta.meta_key = 'featured'
AND ( ( mt1.meta_key = 'area'
AND CAST(mt1.meta_value AS SIGNED) <= '100000' )
AND ( mt2.meta_key = 'price'
AND CAST(mt2.meta_value AS SIGNED) <= '4433356' )
AND ( mt3.meta_key = 'offer_order_status'
AND mt3.meta_value = 'active' ) ) )
AND wp_posts.post_type = 'property'
AND (wp_posts.post_status = 'publish'
OR wp_posts.post_status = 'private')
GROUP BY wp_posts.ID
ORDER BY wp_postmeta.meta_value+0 DESC
LIMIT 0, 12

Und hier ist die $ args-Tabelle, die an die WP_Query übergeben wird:

array (size=7)
  'post_type' => string 'property' (length=18)
  'paged' => int 1
  'meta_key' => string 'featured' (length=21)
  'orderby' => string 'meta_value_num' (length=14)
  'order' => string 'DESC' (length=4)
  'tax_query' => 
    array (size=3)
      0 => 
        array (size=3)
          'taxonomy' => string 'property_type' (length=13)
          'field' => string 'id' (length=2)
          'terms' => string '6' (length=1)
      1 => 
        array (size=3)
          'taxonomy' => string 'transaction_type' (length=16)
          'field' => string 'id' (length=2)
          'terms' => 
            array (size=2)
              0 => string '19' (length=2)
              1 => string '287' (length=3)
      'relation' => string 'AND' (length=3)
  'meta_query' => 
    array (size=4)
      0 => 
        array (size=4)
          'key' => string 'area' (length=17)
          'value' => int 100000
          'type' => string 'NUMERIC' (length=7)
          'compare' => string '<=' (length=2)
      1 => 
        array (size=4)
          'key' => string 'price' (length=18)
          'value' => int 4433356
          'type' => string 'NUMERIC' (length=7)
          'compare' => string '<=' (length=2)
      'relation' => string 'AND' (length=3)
      2 => 
        array (size=3)
          'key' => string 'offer_order_status' (length=31)
          'value' => string 'active' (length=6)
          'compare' => string '=' (length=1)

Hier ist EXPLAIN Ergebnis:

id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra   
1   SIMPLE  wp_term_relationships   ref     PRIMARY,term_taxonomy_id    term_taxonomy_id    8   const   19  Using where; Using index; Using temporary; Using filesort
1   SIMPLE  wp_posts    eq_ref  PRIMARY,post_name,type_status_date,post_parent,post_author  PRIMARY     8   wp_real_estate3.wp_term_relationships.object_id     1   Using where
1   SIMPLE  tt1     ref     PRIMARY,term_taxonomy_id    PRIMARY     8   wp_real_estate3.wp_term_relationships.object_id     2   Using where; Using index
1   SIMPLE  mt3     ref     post_id,meta_key    post_id     8   wp_real_estate3.wp_term_relationships.object_id     12  Using where
1   SIMPLE  mt1     ref     post_id,meta_key    post_id     8   wp_real_estate3.wp_term_relationships.object_id     12  Using where
1   SIMPLE  mt2     ref     post_id,meta_key    post_id     8   wp_real_estate3.wp_term_relationships.object_id     12  Using where
1   SIMPLE  wp_postmeta     ref     post_id,meta_key    post_id     8   wp_real_estate3.wp_term_relationships.object_id     12  Using where

Ich habe viele verwandte Fragen gelesen, kann aber keine Antwort finden, die beschreibt, wie man die Abfrage so ändert, dass sie aussetzt.

Vielen Dank

BEARBEITEN:

Ich habe benutzerdefiniertes SQL erstellt, das anscheinend dieselben Werte mit der Geschwindigkeit von 0,01s zurückgibt:

SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
FROM wp_posts
LEFT JOIN wp_term_relationships
ON (wp_posts.ID = wp_term_relationships.object_id)
LEFT JOIN wp_term_relationships AS tt1
ON (wp_posts.ID = tt1.object_id)
INNER JOIN wp_postmeta
ON ( wp_posts.ID = wp_postmeta.post_id )
WHERE 1=1
AND ( wp_term_relationships.term_taxonomy_id IN (6)
AND tt1.term_taxonomy_id IN (19,287) )
AND ( wp_postmeta.meta_key = 'apartment_wp_featured' )
AND wp_posts.post_type = 'apartment_property'
AND (wp_posts.post_status = 'publish'
OR wp_posts.post_status = 'private')
AND wp_posts.ID IN (
                        SELECT post_id from wp_postmeta
                        WHERE ((meta_key = 'apartment_wp_area' AND CAST(meta_value AS SIGNED) < '100000')
                        or (meta_key = 'apartment_wp_price' AND CAST(meta_value AS SIGNED) < '4433356')
                        or (meta_key = 'apartment_wp_offer_order_status' AND meta_value = 'active'))
                )
GROUP BY wp_posts.ID
ORDER BY wp_postmeta.meta_value+0 DESC
LIMIT 0, 12

Jetzt werde ich versuchen, alle meta_query (die Leistungsprobleme verursachen) als benutzerdefiniertes SQL mit add_filter( 'posts_where' , 'posts_where_statement' ); hinzuzufügen.

1
Johnny

Das ist ein bekanntes Problem mit WordPress und Suchen mit Postmeta.

Ich würde versuchen, eine neue Taxonomie für "Dinge" zu erstellen, nach denen Sie normalerweise am häufigsten suchen:

  • offer_order_status scheint der bessere Kandidat zu sein, da er aktiv sein kann oder nicht. Ich würde eine Taxonomie mit zwei Elementen erstellen. Das würde die Zeit Ihrer Suche erheblich verkürzen
  • Wenn dies nicht ausreicht, würde ich wahrscheinlich als nächsten Schritt versuchen, "Buckets" für die anderen beiden von Ihnen verwendeten "Meta" zu definieren und Taxonomien für diese zu erstellen: Fläche und Preis. Buckets können auf verschiedene Arten erstellt werden: Sie können eine "Größen" -Taxonomie haben, die > 100000, eine andere > 200000 usw. war, und für Preise möchten Sie möglicherweise < 100000, > 100000 && < 200000 tun. Das hängt wirklich davon ab, wie Sie suchen möchten.

Der springende Punkt für Schritt zwei ist, dass Sie sich in die Speicheraktion des Posts einhängen können, um zu "lesen", was der Bereich/die Größe für diese Eigenschaft ist, und dann die richtigen Taxonomien dafür auswählen und sie automatisch im Backend hinzufügen. Auf diese Weise erhalten Sie den Vorteil, dass: a) die Taxonomien immer mit dem tatsächlichen Metawert synchronisiert sind (Sie möchten nicht, dass Personen "die gleichen" oder ähnliche Informationen mehrmals hinzufügen). b) Sie können die "Buckets" der Taxonomien jederzeit ändern, um Ihre "neuen" Anforderungen zu erfüllen: Da Sie den tatsächlichen Wert für diese Felder haben, müssen Sie nur alle Posts erneut "speichern", um die richtigen Taxonomien zu erhalten (Und Sie können das programmatisch tun). c) taxonomiebasierte Suche ist schneller als Metasuche (ist eine indizierte und relativ kleine Tabelle im Vergleich zu Postmeta)


Ein zweiter Ansatz, der in diesem Fall nicht so gut funktioniert, aber dennoch eine Option ist, besteht darin, der Postmeta-Tabelle Indizes hinzuzufügen, die nach post_id, meta_key und meta_value indiziert werden. Das wird auch die Abfrage beschleunigen, indem Indizes verwendet werden, aber wahrscheinlich nicht so viel.

Aber da es viel einfacher zu implementieren ist als das vorherige, würde ich wahrscheinlich zuerst versuchen, diese zweite Option zu implementieren und zu sehen, wie es funktioniert.

1
Xavi Ivars

Angenommen, die Anzahl der Änderungen ist nicht groß pro Tag, können Sie eine "Schatten-DB" in einem besser abzufragenden Format erstellen. Beispielsweise hat jedes Attribut eine eigene Spalte und aktualisiert diese bei jedem Speichern eines Beitrags.

Der Vorteil dieses Ansatzes besteht darin, dass Sie nichts an Ihrer Post/Meta/Terms-Verwendung, keinen Administratorwechsel und keinen Front-End-Code ändern müssen. Der Nachteil ist, dass Sie den Code schreiben müssen, um die Daten anzupassen Jeder Beitrag und jede temporäre Speicherung, die Ihnen mehr Arbeit beim Schreiben des Codes und bei jedem Update auf den DB-Server verschafft.

0
Mark Kaplun