2010-11-18 16 views
1

Ich habe eine Datenbanktabelle, die importierte Informationen speichert. Aus Gründen der Einfachheit seiner etwas wie:MySQL Abfrageoptimierung

CREATE TABLE `data_import` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, 
`amount` DECIMAL(12,2) NULL DEFAULT NULL, 
`payee` VARCHAR(50) NULL DEFAULT NULL, 
`posted` TINYINT(1) NOT NULL DEFAULT 0, 
PRIMARY KEY (`id`), 
INDEX `payee` (`payee`) 
) 

Ich habe auch eine Tabelle, die Importregeln speichert:

CREATE TABLE `import_rules` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, 
`search` VARCHAR(50) NULL DEFAULT NULL, 
PRIMARY KEY (`id`), 
INDEX `search` (`search`) 
) 

Die Idee ist, dass für jede importierte Transaktion, die Abfrage eine einzelne passende Regel versuchen muss finden - Diese Übereinstimmung erfolgt in den Feldern data_import.payee und import_rules.seach. Da beide VARCHAR-Felder sind, habe ich sie indiziert, um die Abfrage schneller zu machen.

Das ist, was ich bisher gefunden habe, scheint gut zu funktionieren. Obwohl langsamer als ich gehofft hatte.

SELECT i.id, i.payee, i.amount, i.posted r.id, r.search 
FROM import_data id 
LEFT JOIN import_rules ir on REPLACE(i.payee, ' ', '') = REPLACE(ir.search, ' ', '') 

Eine Sache, die die obige Abfrage nicht für nicht gerecht zu werden, ist, dass import_data.posted if = 1 ist, dann nicht, ich brauche eine Regel für diese Zeile zu finden - ist es möglich, die Abfrage an diesem Beitritt zu stoppen Reihe? Wenn der Zahlungsempfänger gleich null ist, sollte er es ebenfalls nicht versuchen.

Gibt es noch andere Möglichkeiten, das kann ich optimieren? Ich stelle fest, dass das Erstellen von Text-Joins nicht ideal ist ... nicht sicher, ob es bessere Methoden gibt.

Antwort

2

Die Verwendung von REPLACE() auf dem Join bricht wahrscheinlich die Indizierung, da es einen Index der Werte in dem Feld hat, nicht die geänderten Werte nach REPLACE().

Wenn Sie nicht beitreten, verwenden Sie bereits einen LINKEN JOIN, sodass nicht übereinstimmende Joins zu NULLEN für die Felder import_rules führen; Sie sollten WHERE-Klauseln hinzufügen können, um dies zu erzwingen.

3

Ich empfehle dringend, alles zu tun, um die REPLACE s in diesem JOIN loszuwerden. Die Verwendung von REPLACE auf beiden Seiten des Joins eliminiert die Möglichkeit, einen Index für beide Tabellen zu verwenden.

Angenommen, Sie loszuwerden, die REPLACE s erhalten können (durch die vorhandenen Daten und/oder neue Datenbereinigung):

  • Wenn Sie Notwendigkeit Spalten auf Text zu verbinden, ein einziges Byte pro verwenden Character Zeichensatz, wenn Sie die Anwendung ermöglicht (für einen kleineren/schneller Index).
  • Machen Sie das N in VARCHAR(N) so klein , wie Sie können, wie es die Seite des Index auswirken wird (oder wohl, verwenden Sie den Index Präfixe).
  • Ich stelle mir Sie den search Index auf import_rules UNIQUE machen wollen - dann sind Sie sicher, dass nur 1 row Ergebnis pro Reihe von import_data

zurück gehend erhalten Sie einen AND werfen in Ihre WHERE-Klausel, wenn Sie die Regel "Nicht beitreten in diesem Fall" erzwingen möchten.

LEFT JOIN import_rules ir ON id.payee=ir.search AND id.posted != 1