LW IT Solutions logo LW IT Solutions logo LW IT Solutions
« Blog-Übersicht /WordPress-Plugins & Tricks/Tutorials / Tutorial: Eine langsame meta_query finden und in...
Diesen Artikel in anderen Sprachen lesen:

Tutorial: Eine langsame meta_query finden und in einen Taxonomie-Filter umbauen

Tutorial: Eine langsame meta_query finden und in einen Taxonomie-Filter umbauen
Inhalt
  1. 1. Den vollständigen Filter erhalten
  2. 2. Tatsächliches SQL und Abfrageplan untersuchen
  3. 3. Beide kategorialen Merkmale registrieren
  4. 4. Die Migration vor Schreibzugriffen planen
  5. 5. Verhalten prüfen, bevor Metadaten entfallen
  6. Fragen und Antworten
  7. Quellen

Ein langsamer Produktfilter sollte vor einem Wechsel des Datenmodells gemessen werden. Eine meta_query kann passend sein; eine Taxonomie kann kategoriale Filter unterstützen. Weder die Anzahl der Verbindungen noch die Zahl verschiedener Werte allein sagt die schnellere Lösung voraus. Zuerst muss die neue Abfrage weiterhin dieselben Produkte auswählen.

1. Den vollständigen Filter erhalten

Das Beispiel sucht veröffentlichte Produkte mit Farbe blau, Material eiche und Verfügbarkeit 1. Vorher und nachher müssen alle drei Bedingungen, dieselbe Sortierung und dieselbe Seiteneinteilung gelten. Die Verfügbarkeit bleibt hier eine Metadatenbedingung.

<?php
$base = [
    'post_type' => 'produkt',
    'post_status' => 'publish',
    'posts_per_page' => 20,
    'paged' => 1,
    'orderby' => ['date' => 'DESC', 'ID' => 'DESC'],
];
$before = new WP_Query($base + [
    'meta_query' => [
        'relation' => 'AND',
        ['key' => 'farbe', 'value' => 'blau'],
        ['key' => 'material', 'value' => 'eiche'],
        ['key' => 'verfuegbar', 'value' => '1'],
    ],
]);
$after = new WP_Query($base + [
    'tax_query' => [
        'relation' => 'AND',
        ['taxonomy' => 'farbe', 'field' => 'slug',
         'terms' => ['blau'], 'include_children' => false],
        ['taxonomy' => 'material', 'field' => 'slug',
         'terms' => ['eiche'], 'include_children' => false],
    ],
    'meta_query' => [
        ['key' => 'verfuegbar', 'value' => '1'],
    ],
]);
// SQL: $before->request and $after->request

Der Code setzt den eigenen Beitragstyp produkt sowie beide Taxonomien mit korrekten Zuordnungen voraus. Eine WooCommerce-Abfrage ist das nicht. Zum Vergleich werden zwei Abfragen ausgeführt; die Anwendung würde die gewählte Fassung verwenden. Der Ergebnisabgleich muss alle relevanten Seiten und Filterkombinationen erfassen, nicht nur die ersten zwanzig Treffer.

Filterbedingungen erhalten und Migration prüfen
Filterbedingungen erhalten und Migration prüfen

2. Tatsächliches SQL und Abfrageplan untersuchen

$query->request enthält das erzeugte SQL. Die drei positiven Metadatenbedingungen mit AND benötigen in diesem Beispiel üblicherweise drei Metadatenverbindungen. Eine allgemeine Regel „eine Klausel, eine Verbindung“ folgt daraus nicht: Passende OR-Klauseln können einen Alias gemeinsam verwenden. Logische Tabellenaliase sind keine physischen Kopien der Datenbanktabelle.

Das WordPress-Standardschema indiziert post_id und ein Präfix von meta_key, aber nicht meta_value. Bestehende Installationen können zusätzliche Indizes besitzen. Der Optimierer kann bei der Beitragstabelle oder einem anderen geeigneten Zugriffspfad beginnen; sämtliche Zeilen eines Schlüssels werden nicht zwangsläufig durchsucht. Doppelte Metadatenzeilen können Zwischenergebnisse vergrößern.

Für einen geschützten Entwicklungsaufruf zeichnet SAVEQUERIES SQL, Laufzeit und Aufrufinformationen auf. Das benötigt zusätzlichen Speicher und Rechenzeit; Protokolle können vertrauliche Werte enthalten. Ein Datenbankprotokoll langsamer Abfragen zeigt eine andere Perspektive und liefert nicht denselben PHP-Aufrufpfad. Die Aktivierung benötigt passende Rechte, einen begrenzten Messzeitraum und eine Abschätzung der Protokollmenge. Ein global geänderter Sitzungsvorgabewert aktualisiert nicht jede bestehende Verbindung.

EXPLAIN beschreibt einen geschätzten Plan. rows und filtered gehören zusammen mit Verbindungsreihenfolge, Zugriffstyp und gewählten Indizes gelesen. Eine große Schätzung allein beweist keinen wirkungslosen Filter. Using filesort bedeutet einen zusätzlichen Sortierschritt, nicht zwingend eine Sortierung auf Festplatte. Using temporary ist für sich kein Nachweis einer schlechten Abfrage. MySQLs EXPLAIN ANALYZE führt die Anweisung tatsächlich aus; Syntax und Verhalten unter MariaDB sind gesondert zu prüfen.

meta_value_num sortiert numerisch. WordPress verwendet dafür einen numerischen Ausdruck, keinen Textvergleich. Ausdrücke und große Zwischenergebnisse können den Aufwand erhöhen; die frühere Behauptung, Sortieren koste normalerweise mehr als alle Filter, war jedoch nicht durch Messungen belegt.

3. Beide kategorialen Merkmale registrieren

<?php
add_action('init', function () {
    foreach (['farbe', 'material'] as $taxonomy) {
        register_taxonomy($taxonomy, ['produkt'], [
            'hierarchical' => false,
            'public' => false,
            'publicly_queryable' => false,
            'show_ui' => true,
            'show_admin_column' => true,
            'show_in_rest' => false,
            'query_var' => false,
            'rewrite' => false,
        ]);
    }
});

Registriert werden sowohl farbe als auch material. Das Beispiel deaktiviert öffentliche Taxonomieabfragen und Rewrite-Routen, erlaubt aber die Verwaltung. Eine Zugriffskontrolle entsteht dadurch nicht. Für den Blockeditor ist eine passende REST-Konfiguration einschließlich show_in_rest erforderlich; Veröffentlichung und Berechtigungen der REST-Daten sind gesondert festzulegen.

term_relationships enthält Objekt-ID, Term-Taxonomie-ID und Begriffsreihenfolge. Der zusammengesetzte Primärschlüssel beginnt mit der Objekt-ID; ein eigener Index beginnt mit der Term-Taxonomie-ID. Diese Zugriffspfade können genaue Kategorievergleiche unterstützen. Ein zusammengesetzter Index ist nicht automatisch von beiden Enden gleich gut nutzbar. Ein Ja-Nein-Merkmal ist nicht grundsätzlich ungeeignet für eine Taxonomie. Der Veröffentlichungsstatus sollte nicht lediglich zur Abbildung von Lagerverfügbarkeit umgedeutet werden.

4. Die Migration vor Schreibzugriffen planen

Die folgende plan.php liest ausschließlich. Enthalten sind zwei Beispiel-IDs und ausdrückliche Wertzuordnungen; beide Listen müssen zum tatsächlichen Bestand passen. Die Zielbegriffe müssen bereits existieren. Unbekannte, leere, doppelte oder strukturierte Metadaten brechen die Planung ab, statt Informationen still zu verlieren. Leere Werte benötigen eine festgelegte Regel: Zuordnung erhalten, entfernen oder zur Prüfung markieren.

<?php
// Read-only example for reviewed IDs, not a complete migration runner.
$ids = [101, 102];
$mapping = [
    'farbe' => ['blau' => 'blau', 'rot' => 'rot'],
    'material' => ['eiche' => 'eiche', 'buche' => 'buche'],
];
$plan = [];
foreach ($ids as $id) {
    if (get_post_type($id) !== 'produkt') {
        throw new RuntimeException("Unexpected post type: $id");
    }
    foreach ($mapping as $taxonomy => $values) {
        if (!taxonomy_exists($taxonomy)) {
            throw new RuntimeException("Missing taxonomy: $taxonomy");
        }
        $raw = get_post_meta($id, $taxonomy, false);
        if (count($raw) !== 1 || !is_string($raw[0])
            || !array_key_exists($raw[0], $values)) {
            throw new RuntimeException("Unmapped or ambiguous value: $id/$taxonomy");
        }
        $term = get_term_by('slug', $values[$raw[0]], $taxonomy);
        if (!$term || is_wp_error($term)) {
            throw new RuntimeException("Missing target term: $id/$taxonomy");
        }
        $old = wp_get_object_terms($id, $taxonomy, ['fields' => 'ids']);
        if (is_wp_error($old)) {
            throw new RuntimeException($old->get_error_message());
        }
        $plan[] = [
            'post_id' => $id,
            'taxonomy' => $taxonomy,
            'source_value' => $raw[0],
            'old_term_ids' => array_map('intval', $old),
            'new_term_ids' => [(int) $term->term_id],
        ];
    }
}
echo wp_json_encode($plan, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);

wp eval-file plan.php gibt die vorgesehenen Zuordnungen aus. Begriffszuordnungen und Metadaten werden dabei nicht verändert. Eine vollständige Migration benötigt zusätzlich begrenzte Verarbeitungspakete, eine Sicherung der Quellwerte und bisherigen Zuordnungen, eine Schreibpause oder Synchronisierung sämtlicher Schreiber sowie einen geprüften Wiederaufnahmepfad.

Nach Prüfung des Plans und erneutem Vergleich aktueller Quellwerte und bisheriger Zuordnungen wendet das folgende API-Fragment eine Zeile an. Ganzzahlige Begriffs-IDs vermeiden Verwechslungen mit numerischen Begriffsnamen. Das Argument false ersetzt Zuordnungen innerhalb dieser Taxonomie; vorhandene Begriffe können dadurch entfallen.

<?php
// Fragment for one previously reviewed and revalidated plan row.
$result = wp_set_object_terms(
    (int) $row['post_id'],
    array_map('intval', $row['new_term_ids']),
    $row['taxonomy'],
    false
);
if (is_wp_error($result)) {
    throw new RuntimeException($result->get_error_message());
}
// Read back term IDs and compare them with new_term_ids.

Das Fragment ist kein atomarer Migrationslauf. Jeder Schreibzugriff benötigt Rücklesen und Fehlerbehandlung; ein späterer Fehler setzt frühere Zeilen nicht automatisch zurück. Ein alter Plan kann nach neueren Taxonomieänderungen aktuelle Arbeit überschreiben. Automatische Slug-Normalisierung kann unterschiedliche Quellwerte zusammenführen, weshalb die Zuordnung ausdrücklich festgelegt wird.

5. Verhalten prüfen, bevor Metadaten entfallen

Zum Vergleich gehören Ergebnis-IDs, Reihenfolge, Trefferzahlen, fehlende Werte, doppelte Metadaten, Entwürfe und geplante Inhalte im Migrationsumfang sowie gegebenenfalls mehrsprachige Zuordnungen. Laufzeiten benötigen vergleichbare Daten, Indizes, Cachezustände und Lastbedingungen. Für die früheren Grafikwerte von 480.000 gegenüber 2.100 betrachteten Zeilen liegt keine reproduzierbare Messung vor.

Der frühere Befehl wp post meta delete --all --keys=farbe --dry-run war für diese Aufgabe ungültig. Der dokumentierte Befehl benötigt eine Objekt-ID; --all bezeichnet sämtliche Metadaten dieses Objekts, und ein solcher Dry-run-Schalter ist nicht dokumentiert. Alte Metadaten sollten bis zur Klärung von Schreibern, Vergleichen und Rückweg bestehen bleiben. Die Bereinigung benötigt einen eigenen klaren Umfang und eine Sicherung.

Fragen und Antworten

Wann ist ein anderes Datenmodell sinnvoll?

Zahlenbereiche können von typisierten indizierten Spalten oder einer vorhandenen Nachschlagetabelle profitieren. Kleine oder selektive Metadatenabfragen können bereits schnell sein. Weder tausende Begriffe noch wenige passende Zeilen ergeben eine allgemeingültige Grenze. Volltextindizes zerlegen Text in Suchbegriffe und unterstützen nicht automatisch beliebige Wortteile.

Was gilt bei WooCommerce?

Zuerst sind vorhandene Produkteigenschaften, Sichtbarkeitsregeln und Nachschlagetabellen zu untersuchen. Beitragstyp und Daten-APIs von WooCommerce unterscheiden sich vom erfundenen Beispiel. Eine parallele eigene Taxonomie darf Lagerbestand, Sichtbarkeit, Übersetzungen oder Erweiterungsverhalten nicht umgehen.

Quellen

Lukas Wojcik

Lukas Wojcik

Systems architect and technology enthusiast specializing in scalable tracking solutions, GMP Stack (GA4 & GTM), and robust backend architectures. Advocate for clean code and privacy-first design.

Kontakt

Eine Frage oder eine Idee für ein Webprojekt? Schreib mir kurz, worum es geht. Das Formular nutzt reCAPTCHA zum Schutz vor Spam.

Kommentar schreiben

Erfahrungen mit anderen Plugins oder Hosting-Umgebungen und Rückfragen zur Einrichtung sind hier willkommen.

Die E-Mail-Adresse wird nicht veröffentlicht. Pflichtfelder sind mit einem Stern versehen.