Frage

Ich habe die 3 folgenden Tabellen in einer MySQL 4.x DB:

  • Hosts: (300.000 Datensätze)
    • id (UNSIGNED INT) PRIMARY KEY
    • name (VARCHAR 100)
  • Pfade: (6.000.000 Datensätze)
    • id (UNSIGNED INT) PRIMARY KEY
    • name (VARCHAR 100)
  • Urls: (7.000.000 Datensätze)
    • Host (UNSIGNED INT) PRIMARY KEY <--- Links hosts.id
    • Pfad (UNSIGNED INT) PRIMARY KEY <--- Links paths.id

Wie Sie sehen können, das Schema ist wirklich einfach, aber das Problem ist die Menge an Daten, die in diesen Tabellen.

Hier ist die Abfrage Ich bin mit:

SELECT CONCAT(H.name, P.name)
FROM hosts AS H
INNER JOIN urls as U ON H.id = U.host
INNER JOIN paths AS P ON U.path = P.id;

Diese Abfrage funktioniert perfekt in Ordnung, aber dauert 50 Minuten zu laufen. Hat jemand eine Ahnung, wie ich die Abfrage beschleunigen könnte?

Vielen Dank im Voraus. Nicolas

War es hilfreich?

Lösung

Für eine Sache würde ich die CONCAT in der Abfrage nicht. Tun Sie es außerhalb.

Aber wirklich sind Sie Abfrage läuft langsam, weil Sie Millionen von Zeilen sind abruft.

Andere Tipps

Vielleicht sollten Sie umfassen eine WHERE-Klausel? Oder brauchen Sie wirklich alle Daten?

Das sieht aus wie ein Fall für mich, wo übereifrigen Einsatz von Ersatzschlüsseln wird Sie verlangsamen. Wenn die Tische waren:

  • Hosts:

    • name (VARCHAR 100) PRIMARY KEY
  • Pfade:

    • name (VARCHAR 100) PRIMARY KEY
  • Urls:

    • Host (VARCHAR 100) PRIMARY KEY <--- Links hosts.name
    • Pfad (VARCHAR 100) PRIMARY KEY <--- Links paths.name

Dann würde Ihre Suchabfrage nicht erforderlich schließt sich an alle:

SELECT CONCAT(U.host, U.path) FROM urls U;

True, Tabelle URLS würde mehr Speicherplatz belegen - aber tut das

?

EDIT: Auf den zweiten Gedanken, was ist der Sinn dieser WEGE Tabelle überhaupt? Wie oft teilen verschiedene Hosts die gleichen Pfade?

Warum nicht:

  • Hosts:

    • name (VARCHAR 100) PRIMARY KEY
  • Urls:

    • Host (VARCHAR 100) PRIMARY KEY <--- Links hosts.name
    • Pfad (VARCHAR 100) PRIMARY KEY <--- keine Verbindung zu jedem Ort

EDIT2: Oder wenn Sie wirklich Notwendigkeit die Ersatzschlüssel für Hosts:

  • Hosts:

    • id integer PRIMARY KEY
    • name (VARCHAR 100)
  • Urls:

    • host integer PRIMARY KEY <--- Links hosts.name
    • Pfad (VARCHAR 100) PRIMARY KEY <--- keine Verbindung zu jedem Ort

    SELECT CONCAT (H.name, U.path) FROM Urls U JOIN Hosts H ON H.id = U.host;

Insgesamt ist der beste Rat zu verfolgen und das Profil zu sehen, was wirklich Zeit in Anspruch nimmt ist. Aber hier sind meine Gedanken über bestimmte Dinge zu betrachten.

(1) Ich würde sagen, dass Sie sicherstellen wollen, dass Indizes nicht in der Ausführung dieser Abfrage verwendet werden. Da Sie keine Filterbedingungen haben, sollte es effizienter sein Vollabtast- alle Tabellen und sie dann mit einer Art-Merge oder Hash-Operation miteinander verbinden.

(2) Der String-Verkettung einige Zeit sicher nimmt, aber ich verstehe nicht, warum die Leute es zu entfernen empfehlen. Sie würden vermutlich dann müssen die Verkettung in einem anderen Teil des Codes zu tun, wo es noch etwa die gleiche Menge an Zeit (besonders langsam aus irgendeinem Grund ist die String-Verkettung, es sei denn MySQL) nehmen würde.

(3) Die Daten transferral vom Server an den Client wahrscheinlich viel Zeit nimmt, möglicherweise mehr als die Zeit der Server die Daten holen muss. Wenn Sie Werkzeuge haben diese Art der Sache zu verfolgen, sie verwenden. Wenn Sie die Array-Größe in der Client holen erhöhen können, experimentiert mit verschiedenen Größen (zum Beispiel in JDBC verwenden Statement.setFetchSize ()). Dies kann von Bedeutung sein, auch wenn der Client und Server auf demselben Host ist.

Ich würde versuchen, eine neue Tabelle mit den Daten erstellen Sie erhalten wollen. Dadurch bedeutet, dass Sie einige echte Daten verlieren, aber Sie gewinnen in Schnelligkeit. Könnte diese Idee zu OLAP oder so etwas ähnliches sein?

Natürlich müssen Sie ein Update tun (täglich oder was auch immer) diese Tabelle.

Ich bin kein MySQL-Experte, aber es sieht aus wie MySQL Primärschlüssel geclustert sind - Sie werden sicherstellen möchten, dass der Fall mit Ihrem Primärschlüssel ist; Clustered-Indizes wird auf jeden Fall Geschwindigkeit helfen, die Dingen auf.

Eine Sache, obwohl - ich glaube nicht, dass du zwei „primäre“ Schlüssel auf jedem Tisch haben kann; Ihre Urls Tabelle sieht eher aus diesem Grunde zu mir suspekt. Vor allem sollten Sie unbedingt darauf achten, diese beiden Spalten in der Urls Tabelle auf den Griff indiziert werden - ein einzelner numerischer Index auf jedem sollte in Ordnung sein - weil man auf sie ist Beitritt, so das DBMS wie Sie wissen muss finden sie schnell; das könnte das sein, was in Ihrem Fall vor sich geht. Wenn Sie voll-table-Scannen sind, die viele Zeilen, dann ja, könnten Sie es für einige Zeit sitzen, während der Server alles zu finden versucht, für Sie gefragt.

Ich würde auch vorschlagen, dass CONCAT Funktion aus der select-Anweisung zu entfernen, und zu sehen, wie das Ihre Ergebnisse auswirkt. Ich wäre erstaunt, wenn das irgendwie nicht ein Faktor ist. Nur beide Spalten abrufen und die Verkettung später behandeln, und sehen, wie das geht.

Schließlich haben Sie herausgefunden, wo der Engpass? Gerade Beitritt auf drei mehrere Millionen Zeilen Tabellen nicht viel Zeit überhaupt nehmen sollte (ich würde erwarten, dass vielleicht eine Sekunde oder so, nur die Tabellen und Abfrage Anglotzen), sofern die Tabellen korrekt indiziert sind. Aber wenn Sie diese Zeilen über eine langsame oder bereits gebunden NIC, an einen Speicher-ausgehungert App-Server zu drücken usw., könnte die Langsamkeit nichts mit Ihrer Anfrage zu tun, überhaupt, sondern mit dem, was nach der Abfrage geschieht. Sieben Millionen Zeilen sind ein bisschen von Daten um zu Montage und bewegt, und zwar unabhängig davon, wie lange die Feststellung dieser Zeilen nehmen geschieht. Versuchen Sie, nur eine Zeile auswählen, anstatt, anstatt alle sieben Millionen, und sehen, wie das dagegen sieht. Wenn das schnell ist, dann ist das Problem nicht die Abfrage, es ist das Ergebnis gesetzt.

Als Ergebnismenge liefert alle Daten, gibt es sehr wenig Optimierung, die überhaupt durchgeführt werden kann. Sie scannen die gesamte Tabelle, dann auf anderen Tabellen verknüpft, die Indizes haben.

Sind die PrimaryKeys Clustered? Dadurch wird sichergestellt, dass die Daten auf der Platte in der Indexreihenfolge gespeichert sind, so zu vermeiden prallen verschiedene Teile der Platte.

Sie können aber auch die Daten verteilt auf mehrere Festplatten haben. Wenn Sie URLs auf PRIMARY und WEGE / hosts auf SECONDARY haben, dann werden Sie besser Durchsatz von den Antrieben erhalten.

Sie müssen sich auf die Serverkonfiguration suchen. Die Standardspeicherparameter für MySQL wird die Leistung auf einem Tisch lahmlegen, dass Größe. Wenn Sie die Standardeinstellungen verwenden, müssen Sie mindestens key_buffer_size und join_buffer_size um mindestens einen Faktor von 4, vielleicht noch viel mehr zu erhöhen. Schauen Sie in der Dokumentation; es gibt auch andere Speicherparameter Sie zwicken können.

MySQL eine lustige Performance Marotte hat, wo, wenn Sie Ihre Tabellen mit Abfragen über eine bestimmte Größe gehen, die die meisten Daten zurückkehren, geht Leistung in die Toilette. Leider hat es keine Möglichkeit, Ihnen zu sagen, wenn diese Schwelle erreicht ist. Es scheint mir, wie Sie haben, though.

Versuchen Sie, Ihre Tabellen zu optimieren, bevor Sie die Abfrage ausführen:

optimize table hosts, paths, urls;

Es könnte Sie einige Zeit sparen, vor allem, wenn Zeilen aus den Tabellen gelöscht wurden. (Siehe hier für weitere Informationen über OPTIMIZE)

Haben Sie bereits erklärt, einige Indizes für die Join-Attribute?

PS: Siehe hier [defekter Link] für Indizes auf MySQL 4.x

Die Concat definitiv verlangsamt Sie nach unten. Können wir die Ergebnisse einer mysql auf das erklären? Dokumentation Link-

Die größte Sache zu tun ist, um zu versuchen, nur die Daten, die Sie benötigen allerdings zu ziehen. Wenn Sie weniger Datensätze ziehen, die Sie so viel wie etwas beschleunigen wird. Aber ein mysql erklären sollte uns sehen helfen, wenn alle Indizes helfen würde.

Ich verstehe, dass Sie eine vollständige Liste der URLs wollen - die 7 Millionen Datensätze ist. Vielleicht wie von Mitch sugested Sie berücksichtigen sollten, mit der Klausel WHERE Ihre Ergebnisse zu filtern. Vielleicht ist der Zeitpunkt vor allem auf die Verzögerung verknüpften Datensätze in der Anzeige

Prüfzeit für diese Abfrage

select count(*)
FROM hosts AS H
INNER JOIN urls as U ON H.id = U.host
INNER JOIN paths AS P ON U.path = P.id

Wenn dies immer noch langsam ist, würde ich gehen und überprüfen Timing für     SELECT COUNT (*) von URLs,

dann

select count(*) 
from urls u 
inner join hosts h on u.host = h.id

dann

select count(*) 
from urls u 
inner join hosts h on u.host = h.id
inner join paths p on u.path = p.id

nur die Quelle der langsam nach unten

lokalisieren

Auch manchmal Ihre Anfrage Neuordnungs kann helfen,

SELECT CONCAT(u.host, u.path)
from urls u 
inner join hosts h on u.host = h.id
inner join paths p on u.path = p.id

Ich kann nicht sicher sagen, über mySQL aber ich weiß, in SQL Server, die Primärschlüssel einen Index automatisch erstellen, aber Fremdschlüssel nicht. Achten Sie darauf, zu prüfen, ob es ein Index auf den Fremdschlüsselfeldern.

Da ich bin kein großer Fan von MySQL, würde ich fragen, ob Sie PostgreSQL versucht haben. In dieser DB, wollen Sie sicherstellen, dass Ihre work_mem Einstellung recht hoch war, aber man kann es per DB-Verbindung mit SET work_mem Set = 64 MB, zum Beispiel.

Ein weiterer Vorschlag ist in mit doppelten Pfadeinträgen zu suchen. Es sind viele URLs, die Freigabepfade.

Eine andere Sache, die Text mit fester Länge Felder statt Varchars könnte oder nicht, wird mit helfen könnte. Es verwendet, um eine Geschwindigkeitsdifferenz zu machen, aber ich bin mir nicht sicher über die aktuellen DB-Motoren.

Wenn Sie PostgreSQL verwenden Sie es lassen Sie JOIN verwenden verwenden, aber auch auf MySQL Ich mag es mehr: benennen Sie Ihre ID-Feld in jeder Tabelle gleich. Anstelle von ID in Hosts und Host in Urls, Name host_id es beide Orte.

Jetzt sind einige weitere Kommentare. :) Diese Daten Layout, das Sie hier haben, ist sehr nützlich, wenn Sie eine kleine Menge von Zeilen auswählen, vielleicht jede URL aus der gleichen Domäne. Es kann auch ein Los helfen, wenn Ihre Fragen tun müssen, oft sequenziellen Scans der Tabelle Urls für andere Daten dort gespeichert, da der Scan über die großen Textfelder überspringen kann (Es sei denn, es nicht, weil keine Rolle Ihr DB speichert Text über Zeiger zu einer verknüpften Tabelle sowieso).

Wenn Sie jedoch fast immer wählen Sie alle Domäne und Pfaddaten, dann macht es mehr Sinn, es zu speichern, in einer Tabelle.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top