Ich habe wild gegoogelt versucht, dies herauszufinden, mit überraschend wenig Glück; Ich denke, das ist ein häufiges Problem.Verknüpfen und Durchsuchen mehrerer MySQL-Tabellen mit Eins-zu-viele-Beziehungen
Ich habe 5 Tabellen: Bestellungen, Adressen, Notizen, Transaktionen, line_items und Sendungen.
transactions
, addresses
und notes
alle haben order_id
Felder indiziert - line_items
und shipments
haben transaction_id
Felder indiziert.
Die beste Single-Abfrage-Leistung, die ich bekommen habe, ist völlig unhaltbar - über 30 Sekunden manchmal. Die große und frustrierende Ironie ist, dass ich dies mit einem großen Block PHP-Code unter 1 tun kann. Zum Beispiel werde ich alle Notizen durchgehen, um sie mit einer gegebenen Suche abzugleichen und alle order_ids in einem Array zu speichern. Dann mache ich das gleiche für alle anderen Tische. Dann werde ich eine massive IN (...) Anweisung an meine letzte Abfrage der Tabelle Bestellungen anhängen. Das funktioniert gut, aber ich weiß, dass ich es besser machen kann.
Die offensichtlichsten Routen funktionieren nicht; einfach LINKE JOIN all diese Tabellen zu den ursprünglichen Bestellungen Tabelle und GROUPING von der order.id dauert zu lang - etwa 9 Sekunden.
Für das Leben von mir kann ich nicht sehen, wie meine janky PHP-Lösung effizienter ist, dass mysql all diese Berechnungen intern durchführt.
ich diese so oft neu geschrieben habe, kann ich es kaum, all die verschiedenen Dinge erinnern, die ich versucht habe ... Ich denke, das ist mein erster Versuch war:
SELECT o.id FROM orders o
LEFT JOIN addresses a ON a.order_id = o.id
LEFT JOIN notes n ON (n.parent_id = o.id AND n.type = "parts")
LEFT JOIN transactions t ON t.order_id = o.id
LEFT JOIN line_items li ON li.transaction_id = t.id
LEFT JOIN shipments s ON s.transaction_id = t.id
WHERE 0 = 0
AND ((a.`email` LIKE "%Lachman%" || a.`contact_name` LIKE "%Lachman%" || a.`company_name` LIKE "%Lachman%" || a.`address1` LIKE "%Lachman%" || a.`address2` LIKE "%Lachman%" || a.`country` LIKE "%Lachman%" || a.`city` LIKE "%Lachman%" || a.`region` LIKE "%Lachman%" || a.`postal_code` LIKE "%Lachman%" || n.`note` LIKE "%Lachman%" || t.`g_order_number` LIKE "%Lachman%" || t.`pp_txn_id` LIKE "%Lachman%" || t.`fm_invoice_num` LIKE "%Lachman%" || t.`ebay_item_id` LIKE "%Lachman%" || t.`ebay_buyer_id` LIKE "%Lachman%" || t.`ebay_transaction_id` LIKE "%Lachman%" || t.`ebay_order_id` LIKE "%Lachman%" || li.`partnum` LIKE "%Lachman%" || li.`part_id` LIKE "%Lachman%" || li.`desc` LIKE "%Lachman%" || li.`source` LIKE "%Lachman%" || s.`tracking` LIKE "%Lachman%" || s.`carrier` LIKE "%Lachman%"))
GROUP BY o.id
ORDER BY `created` DESC
2 Ergebnisse 9,6895699501 Sekunden
ich bin nicht sicher, wie genau die Formatierung auf das sein wird, aber ich werde befestigt auch die Erklärung:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE o ALL NULL NULL NULL NULL 2840 Using temporary; Using filesort
1 SIMPLE a ref order_id order_id 5 apple_components.o.id 1
1 SIMPLE n ref parent_id,type type 22 const 314
1 SIMPLE t ref order_id order_id 5 apple_components.o.id 1
1 SIMPLE li ref transaction_id transaction_id 4 apple_components.t.id 1
1 SIMPLE s ref transaction_id transaction_id 4 apple_components.t.id 1 Using where
vielen, vielen dank.
[Edit: Referenz, hier ist die PHP-Lösung, die ~ 0,02 s dauert - wie kann ich das tun, in gerade mysql !?]
if ($s['s']) {
$search_fields = array(
'a' => array('email', 'contact_name', 'company_name', 'address1', 'address2', 'country', 'city', 'region', 'postal_code'),
'n' => array('note'),
't' => array('g_order_number', 'pp_txn_id', 'fm_invoice_num', 'ebay_item_id', 'ebay_buyer_id', 'ebay_transaction_id', 'ebay_order_id'),
'li' => array('partnum', 'part_id', 'desc', 'source'),
's' => array('tracking', 'carrier')
);
$search_clauses = array();
foreach ($search_fields as $table => $fields) {
$the_fields = array();
foreach ($fields as $field) $the_fields[] = $table.'.`'.$field.'`';
$clauses = array();
foreach (explode(' ', $s['s']) as $term) $clauses[] = 'CONCAT_WS(" ", '.implode(', ', $the_fields).') LIKE "%'.$term.'%"';
$search_clauses[$table] = $clauses;
}
$order_ids = array();
$results = mysql_query('SELECT order_id FROM addresses a WHERE '.implode(' AND ', $search_clauses['a']));
while ($result = mysql_fetch_assoc($results)) $order_ids[] = $result['order_id'];
$results = mysql_query('SELECT parent_id FROM notes n WHERE type = "orders" AND '.implode(' AND ', $search_clauses['n']));
while ($result = mysql_fetch_assoc($results)) $order_ids[] = $result['parent_id'];
$results = mysql_query('SELECT order_id FROM transactions t WHERE '.implode(' AND ', $search_clauses['t']));
while ($result = mysql_fetch_assoc($results)) $order_ids[] = $result['order_id'];
$transaction_ids = array();
$results = mysql_query('SELECT transaction_id FROM line_items li WHERE '.implode(' AND ', $search_clauses['li']));
while ($result = mysql_fetch_assoc($results)) $transaction_ids[] = $result['transaction_id'];
$results = mysql_query('SELECT transaction_id FROM shipments s WHERE '.implode(' AND ', $search_clauses['s']));
while ($result = mysql_fetch_assoc($results)) $transaction_ids[] = $result['transaction_id'];
if (count($transaction_ids)) {
$results = mysql_query('SELECT order_id FROM transactions WHERE id IN ('.implode(', ', $transaction_ids).')');
while ($result = mysql_fetch_assoc($results)) if (!empty($result['order_id'])) $order_ids[] = $result['order_id'];
}
}
$query = 'SELECT id FROM orders WHERE id IN ('.implode(', ', $order_ids).')';
2009-10-07: bei dieser Suche wieder ; habe immer noch keine bessere Lösung gefunden. Der Vorschlag in den Kommentaren, "FORCE INDEX (PRIMARY)" nach "orders o" einzufügen, hat konsequent ein paar Sekunden abgeschlagen - aber ich habe nie wirklich verstanden warum. Außerdem habe ich festgestellt, dass meine PHP-Lösung dadurch eingeschränkt ist, dass Suchen mit mehreren Begriffen nur innerhalb einer Tabelle und nicht über mehrere Tabellen hinweg abgeglichen werden.
Ich bin mir nicht sicher, ob ich das CONCAT tun würde. Immer wenn Sie LIKE mit einem berechneten Wert vergleichen, muss der Server nacheinander alle Zeilen durchlaufen. Wenn Sie LIKE mit den direkten Zeilen in der Tabelle vergleichen (und Sie haben eine Art Volltextindex in der Datenbank), kann der Server stattdessen den Index überprüfen. (Wenn es jedoch keinen Volltextindex gibt, müssen Sie alle Zeilen durchgehen, da am Anfang der Zeichenfolge ein% steht.) –
Mit anderen Worten, Sie haben den Text der Abfrage vereinfacht, aber Sie " Die eigentliche Datenbanksuche wurde komplizierter. –
Ja, aber ich gehe davon aus, dass das LIKE fast augenblicklich ist, es sind die Joins, die Verlangsamung verursachen. – rooskie