Hier sind einige Dinge, die ich versuchen würde, in der Reihenfolge zunehmender Schwierigkeit:
(einfacher) - Stellen Sie sicher, dass Sie den richtigen Deckindex haben
CREATE INDEX ix_temp ON relations (relation_title, object_title);
Dies sollte die Leistung angesichts Ihres vorhandenen Schemas maximieren, da (es sei denn, Ihre Version des mySQL-Optimierers ist wirklich dumm!) die Menge an I/Os minimiert wird, die zur Erfüllung Ihrer Abfrage erforderlich sind (anders als wenn der Index in umgekehrter Reihenfolge ist, wo der gesamte Index muss gescannt werden) und deckt die Abfrage ab, sodass Sie den gruppierten Index nicht berühren müssen.
(etwas schwieriger) - Stellen Sie sicher, dass Ihre Varchar-Felder so klein wie möglich sind
Eine der Leistungsherausforderungen bei varchar-Indizes auf MySQL besteht darin, dass bei der Verarbeitung einer Abfrage die volle deklarierte Größe des Felds in den Arbeitsspeicher gezogen wird. Wenn Sie also ein varchar(256) haben, aber nur 4 Zeichen verwenden, zahlen Sie immer noch die 256-Byte-RAM-Nutzung, während die Abfrage verarbeitet wird. Autsch! Wenn Sie also Ihre Varchar-Limits leicht verkleinern können, sollte dies Ihre Abfragen beschleunigen.
(härter) - Normalisieren
30 % Ihrer Zeilen mit einem einzelnen Zeichenfolgenwert sind ein klarer Ruf nach Normalisierung in eine andere Tabelle, damit Sie Zeichenfolgen nicht millionenfach duplizieren. Erwägen Sie, in drei Tabellen zu normalisieren und Ganzzahl-IDs zu verwenden, um sie zu verbinden.
In einigen Fällen können Sie unter der Decke normalisieren und die Normalisierung mit Ansichten ausblenden, die mit dem Namen der aktuellen Tabelle übereinstimmen. Dann müssen Sie nur Ihre INSERT/UPDATE/DELETE-Abfragen auf die Normalisierung aufmerksam machen, können aber Ihre SELECTs in Ruhe lassen .
(am schwierigsten) – Hashen Sie Ihre String-Spalten und indizieren Sie die Hashes
Wenn das Normalisieren bedeutet, zu viel Code zu ändern, Sie Ihr Schema aber ein wenig ändern können, sollten Sie erwägen, 128-Bit-Hashes für Ihre Zeichenfolgenspalten zu erstellen (unter Verwendung des MD5-Funktion ). In diesem Fall müssen Sie (anders als bei der Normalisierung) nicht alle Ihre Abfragen ändern, sondern nur die INSERTs und einige der SELECTs. Auf jeden Fall möchten Sie Ihre Zeichenfolgenfelder hashen und dann einen Index für die Hashes erstellen, z.
CREATE INDEX ix_temp ON relations (relation_title_hash, object_title_hash);
Beachten Sie, dass Sie mit SELECT herumspielen müssen, um sicherzustellen, dass Sie die Berechnung über den Hash-Index durchführen und nicht den Clustered-Index einlesen (erforderlich, um den tatsächlichen Textwert von object_title aufzulösen, um die Abfrage zu erfüllen).
Wenn relation_title eine kleine varchar-Größe hat, aber object title eine lange Größe hat, dann können Sie möglicherweise nur object_title hashen und den Index auf (relation_title, object_title_hash)
erstellen .
Beachten Sie, dass diese Lösung nur hilft, wenn eines oder beide dieser Felder im Verhältnis zur Größe der Hashes sehr lang ist.
Beachten Sie auch, dass Hashing interessante Auswirkungen auf die Groß-/Kleinschreibung/Sortierung hat, da der Hash einer Zeichenfolge in Kleinbuchstaben nicht mit dem Hash einer Zeichenfolge in Großbuchstaben identisch ist. Sie müssen also sicherstellen, dass Sie die Zeichenfolgen kanonisieren, bevor Sie sie hashen – mit anderen Worten, hashen Sie nur Kleinbuchstaben, wenn Sie sich in einer DB befinden, bei der die Groß-/Kleinschreibung nicht berücksichtigt wird. Möglicherweise möchten Sie auch Leerzeichen am Anfang oder am Ende kürzen, je nachdem, wie Ihre DB mit führenden/nachgestellten Leerzeichen umgeht.