2010-06-28 18 views
5

Die folgende Abfrage funktioniert, aber es ist sehr langsam für 10 Datensätze (2 Sekunden). Das Profiling sagt, dass es einen TMP-Tisch erstellt, aber ich bin mir nicht sicher warum.MySQL - Wie kann diese Abfrage optimiert werden?

Grundsätzlich schließe ich mich dem aktuellen Benutzer, den acl-Gruppen an, um alle Gruppen, in denen sie sich befinden, den Gruppen beizutreten, um alle Unternehmen zu erhalten, in denen sie sich befinden, und dann den Firmen zu den Aufträgen beizutreten , um alle Aufträge zu bekommen ..

Wenn ich diese Zeile

ORDER BY orders.created_on DESC 
entfernen

dann die Abfrage ausgeführt in 0,06 Sekunden (mehr als akzeptabel) ..

Hilfe, alle Ideen auf, wie zu optimieren ? Vielen Dank :)

SELECT 
    orders.uuid, 
    companies.name as company_name 
FROM 
    users u 
JOIN  
    users_acl_groups g on u.uuid = g.user_uuid 
JOIN 
    users_acl acl on (acl.user_uuid = u.uuid or acl.group_uuid = g.group_uuid) 
JOIN 
    companies on acl.item_uuid = companies.uuid 
JOIN 
    orders on companies.uuid = orders.company_uuid 
WHERE 
    u.uuid = 'DDEC8073-5056-C000-01ED583A51CBCA32' and orders.status <> '' 
ORDER BY orders.created_on DESC 

limit 0, 10; 

UPDATE, erklären die der Abfrage ..

1 SIMPLE Aufträge ALL 9403 Mit vorübergehend; Verwenden von filesort

1 EINFACH acl ALL 1859 Verwenden wo; Verwendung des Verbindungspuffers

1 EINFACH g ALL 2005 Verwendung wo; beitreten Mit Puffer

1 SIMPLE Unternehmen eq_ref Primär Primär 52 table.orders.company_uuid 1

1 EINFACH u ALL 33595 verwenden, wo; klar; -Join-Puffer

+0

Geändert Ihren Titel, als Raten, dass es kostet Sie einen Downvote aufgrund seiner imperativen und anspruchsvollen Ton, wenn Ihre Frage ist gut formuliert. –

+0

Versuchen Sie, dieselbe Abfrage mit Join zu verwenden, die auf eine andere Spalte als die UID angewendet wird. Versuchen Sie es mit int, float, string, UID und beachten Sie die Zeit. Lassen Sie uns auch wissen, wenn Sie eine Variation finden. –

+0

Haben Sie einen Index für orders.created_on? Zeigen Sie die Ausgabe auf EXPLAIN in Ihrer Abfrage an. Vielleicht könnten Sie von anderen Indizes profitieren. Welche EXPLAIN wird uns sagen. – nos

Antwort

2

Sie haben als ein Faktentabelle Stil Design machen, als Normalisierungsschritt?

Im Grunde ist es eine Art von many-to-many-Verknüpfungstabelle, zum Beispiel:

CREATE TABLE user_order_fact (
    user_uuid ... 
    order_uuid ... 
    order_created_on ... 
    order_status ... 
    company_name ..., 
    primary key (user_uuid, order_uuid), 
    key (user_uuid, order_status, order_created_on, order_uuid, company_name) 
); 

... fill with data ... 

SELECT 
    order_uuid, 
    company_name 
FROM 
    user_order_fact 
WHERE 
    user_uuid = 'DDEC8073-5056-C000-01ED583A51CBCA32' and order_status <> '' 
ORDER BY order_created_on DESC 

limit 0, 10; 

ich auf der Verbindung Index bin zu raten. Sie müssen experimentieren, bis Sie es richtig verstanden haben. Im Grunde versuchen Sie, den Optimierer-Plan zu melden, dass er Index verwendet.

Natürlich speichert dies Daten redundant und in denormalisierter Form, daher müssen Sie einige Trigger einrichten, um dies mit den normalisierten Tabellen synchron zu halten.

+0

Hmm vielleicht ist die PK nur order_uuid. Ich garantiere nicht, dass dies das beste Design ist, nur um Ihnen ein Gefühl zu geben, was ich meine. –

0

Stellen Sie sicher, dass "orders.created_on" einen Index hat ... Wenn dies der Fall ist, dann wird Bills Ansatz am besten sein, wird aber ein wenig Arbeit erfordern.

+0

Ich denke es tut? KEY 'created_on' (' created_on') – Brett

0

Schwer zu beantworten, ohne viel über die vorhandenen Indizes oder das Volumen jeder Tabelle zu wissen.

Abgesehen davon, ohne viele Informationen über das Modell ... gibt die Abfrage alle Ergebnisse zurück?

Gehören alle Benutzer zu einer Gruppe? Es scheint, dass nicht ... und die Abfrage wird keine Benutzer außerhalb einer Gruppe zurückgeben.

Kann eine Gruppe zu einer Gruppe gehören, die eine rekursive Abfrage aufruft?

+0

Ich habe versucht, diese rekursive Abfrage-Sache zu arbeiten, aber ich hatte nicht viel Glück :(Die Tabelle ist leise klein, 10.000 Datensätze alle oben. Es gibt keine Indizes im Moment .. – Brett

+0

@Brett: Indizes, falls in diesem Fall vorhanden, werden nicht funktionieren, da NOT Operator und Like Operator keine Indizes verwenden –

0

Ich bin mir nicht sicher, was genau der Grund sein könnte, dass es 2 Sekunden dauert. Welches ist für diese Abfrage Abrufen von 10 Datensätze nicht möglich, aber was zu sehen sind hier ist

  1. acl.user_uuid = u.uuid or acl.group_uuid = g.group_uuid

    UID auf Basis beitreten, können Sie auch es als Primärschlüssel als oben beantwortet.

  2. ORDER BY orders.created_on. Die Verwendung von Order by auf date wäre nicht so optimal wie die Verwendung von PK oder irgendein ganzzahliger Wert ist geeigneter.

  3. orders.status <> '' Bei der Verwendung von all Indizes auf Tabellen dann kein Index kann in dieser Abfrage verwendet werden, da NOT Operator und wie Operator keine Indizes verwendet, wenn in einer Abfrage verwendet.

  4. Die Anzahl der Datensätze in einer Tabelle könnte ein anderer Grund sein, aber nur aufgrund der oben genannten Faktoren. Sonst hätte es auch große Mengen verarbeiten können.

wichtiger Faktor, dass ich denke, ist UID in Joins können also verwendet werden, alle drei zu vermeiden Bedingungen in der Abfrage zu sehen, die Ihre Suchanfrage faul

+0

Hallo, danke für deine Antworten. Was bedeutet minimiert in Nr.2? – Brett

0

paar Ideen machen könnten:

Sie wählen in Ihrer Abfrage nicht orders.created_on. Es hat also keinen Sinn, nach dieser Spalte zu sortieren. Vielleicht würde es (SELECT orders.created_on ...) die Leistung helfen (nur wetten - ich habe keine Ahnung, was ich hier spreche).

Sie können Ihre Anwendung immer sortieren - wenn Ihre Anfrage nicht eine enorme Menge an Datensätzen enthält.

Manchmal ist es leistungsfähiger, N kleine Abfragen anstelle von 1 großen SQL-Abfrage zu verwenden. Pseudo-Code:

Verwandte Themen