2010-12-11 6 views
3

Ich bin neu bei MySql und Datenbanken im Allgemeinen. Ich habe eine Abfrage, die ich über Snippets aus Online-Ressourcen und Trail & Error zusammengebaut habe. Es ist wirklich langsam (27sec) und ich nehme an, dass es optimiert werden kann. Vielleicht könnte mir jemand dabei helfen.mySQL Abfrage für die obersten N Einträge eines gruppierten Datensätze

Dies ist die Datenstruktur für meine mySQL - Datenbank. Version 5.1.51-0

|- purchaseID -|- customerID -|- emotionID -|- customerCountryCode -|- customerContinentCode-| 
|  1  |  2345  |  0  |  US    |   NA   | 
|  2  |  2345  |  3  |  US    |   NA   | 
|  3  |  4456  |  0  |  UK    |   EU   | 
|  3  |  4456  |  5  |  UK    |   EU   | 
|  4  |  4456  |  2  |  UK    |   EU   | 
|  5  |  4456  |  2  |  UK    |   EU   | 
|  6  |  1234  |  0  |  US    |   NA   | 
|  7  |  6678  |  0  |  US    |   NA   | 
|  8  |  9900  |  0  |  US    |   NA   | 
|  9  |  3334  |  0  |  US    |   NA   |  
|  10  |  3334  |  4  |  US    |   NA   | 

Die Datenbank wird verwendet, um alle getätigten Einkäufe zu speichern. Bei jedem Kauf wird der customerID, das Land und der Kontinent, aus dem er kommt, gespeichert. Der Kunde hat auch die Möglichkeit, seinen Einkauf aus einer Reihe von 6 Emotionen zu bewerten. (glücklich, enttäuscht, ...) Die Emotion, die er wählt, wird gespeichert als emotionID.

So jetzt brauche ich eine Abfrage, um mir die Top 6 Kunden für eine bestimmte emotionID mit einem Prozentsatz Informationen zu bekommen. Angenommen, ich für emotionID = 0 sah das ist, was ich möchte bekommen:

|- customerID -|- emotionPercent -| 
|  1234  |  100  |  
|  6678  |  100  |  
|  9900  |  100  | 
|  2345  |  50  |  
|  3334  |  50  | 
|  4456  |  25  |  

Ich bin mit dieser Abfrage:

SELECT customers.customerID, Count(customers.emotionID)/C.totalPeople * 100.0 AS emotionPercent 
FROM `customers` 
INNER JOIN 

    (SELECT customers.customerID, Count(customers.emotionID) AS totalPeople 
    FROM `customers` 
    GROUP BY customerID) C 

ON customers.customerID = C.customerID 
WHERE customers.emotionID = 0 
GROUP BY customers.customerID 
ORDER BY emotionPercent DESC 
LIMIT 0,6 

Ich habe nach Antworten gesucht, aber der zusätzliche prozentuale Berechnung wird mir werfen aus. Ich habe einige Lösungen gefunden, die eine temporäre Tabelle auffüllen müssten, aber ich konnte es nicht zum Laufen bringen.

Problem ist: Derzeit sind 140.000 Einträge in der Datenbank und diese Abfrage dauert etwa 27 Sekunden. Kann das richtig sein? Würde die Verwendung eines SQL - Servers die Geschwindigkeit deutlich erhöhen?

Was ich nicht bekommen, ist dies: Eingestellte das glücklichste Land der Welt Blitz schnell (0,4 Sekunden), aber strukturell ähnlich der ersten Abfrage (27 sec):

SELECT customers.customerCountryCode, Count(customers.emotionID)/C.totalPeople * 100.0 AS emotionPercent 
FROM `customers` 
INNER JOIN 

    (SELECT customers.customerCountryCode, Count(customers.emotionID) AS totalPeople 
    FROM `customers` 
    GROUP BY customerCountryCode) C 

ON customers.customerCountryCode = C.customerCountryCode 
WHERE customers.emotionID = 0 
GROUP BY customers.customerCountryCode 
ORDER BY emotionPercent DESC 
LIMIT 0,6 

Als ich Ändern Sie die GROUP BY der INNER Query in diesem Beispiel zu customerID, dauert die Abfrage auch für immer. Es ist also die Gruppierung von customerID, die das Problem verursacht. Aber warum?

Die customerCountryCode ist definiert als varchar(2). Die customerID ist eine int(11). Verursacht dies den großen Unterschied in der Abfrageleistung? Gibt es einen geeigneteren Variablentyp? Die customerID kann bis zu 8 Nummern haben.

Eine Menge Fragen! Danke fürs Lesen und jede Hilfe!

Antwort

0

Zuerst, wenn Sie denken, dass die Einträge in Ihrer Datenbank werden ballooning, oder wenn Ihre Einträge hoch sind und der Server langsam wie es ist, IMHO, möchten Sie die Daten vorverarbeiten und speichern Sie sie in einer anderen Datenbank die zusammengefassten Ergebnisse, auf diese Weise müssten Sie nicht den gleichen Prozess immer wieder anfordern. Versuchen Sie auch, Caching-Plugins für Ihre App zu verwenden. Memcache für PHP oder ehcache auf j2ee wäre sicher Wetten.

+0

Hallo rapi schreiben! Danke für deine Antwort. Ich habe nicht über die Vorverarbeitung meiner Daten nachgedacht. Ich werde es mir ansehen. –

0

Ihr Problem könnte sein, dass Sie Unterabfragen verwenden. Da Unterabfragen keine Indizes verwenden oder festlegen, verwenden sie die langsamste Join-Methode, die möglich ist (d. H. Eine vollständige Tabellensuche). Ich bin nicht erfahren genug, um eine SQL-only-Lösung anzubieten, daher würde ich empfehlen, die Abfrage in zwei separate Aufrufe aufzuteilen.

  1. Erhalten Sie durchschnittliche Emotionen für jeden Kunden und wählen Sie Top 6, speichern Sie in Hash oder Objekt.
  2. diese 6 Kunden über WHERE custumerID IN (id1, id2, id3, etc)

Get Obwohl dies wahrscheinlich nicht die schönste von Lösungen ist, können Sie mit einem Index-weniger Unterabfrage (und den sehr langsamen Full Table Scan) vermeiden.

0

Vielen Dank für Ihre Hilfe!

Die Jungs aus dem mySQL-Forum vorgeschlagen, einige Indizes hinzuzufügen:

ALTER TABLE customers 
    ADD KEY idx_country_emid (customerCountryCode, emotionID), 
    ADD KEY idx_emid_custid (emotionID, customerID); 

Die Abfragezeit von 27 Sekunden auf 0,1 Sekunden gesunken. ;)

Auch für die innere Abfrage können Sie

(SELECT customers.customerCountryCode, Count(*) AS totalPeople 
    FROM `customers` 
    GROUP BY customerCountryCode) C 
Verwandte Themen