2012-09-21 8 views
8

Ich habe eine Tabellenstruktur wie folgt aus:bekommen viele gruppiert Werte von mysql

CREATE TABLE `test` (
    `a` tinyint(3) unsigned DEFAULT 0, 
    `b` tinyint(3) unsigned DEFAULT 0, 
    `c` tinyint(3) unsigned DEFAULT 0, 
    `d` tinyint(3) unsigned DEFAULT 0, 
    `e` tinyint(3) unsigned DEFAULT 0 
); 

Dies hat etwa 30 Spalten mit einigen Spalten, die Werte von 0 bis 200 haben (a, b) und einige haben nur 5 Werte (0,1,2,3,4) (Spalte cd). Es gibt ungefähr. 120.000 Zeilen in der Tabelle.

Um die Anzahl der Artikel pro Zeile anzeigen verwende ich eine Abfrage für jede Spalte:

select a, count(*) FROM test group by a; 
select b, count(*) FROM test group by b; 
select c, count(*) FROM test group by c; 
select d, count(*) FROM test group by d; 
select e, count(*) FROM test group by e; 

Das Problem dabei ist, dass es 30 Anfragen ausgelöst wird (eine pro Spalte) und im Grunde den gleichen Satz geht über von Daten jedes Mal.

Gibt es einen besseren Weg, dies zu tun?

Ich habe versucht, mit GROUP BY WITH ROLLUP, aber dies führt zu einer massiven Ergebnismenge, die langsamer als jede einzelne Abfrage verarbeitet wird.

Sie können eine Auswahl der Daten auf SQLfiddle anzuzeigen: http://sqlfiddle.com/#!2/a9fd8/1

+0

Everytime 'Using temporary; Mit filesort' können Sie sortierte Indizes zu Ihren Spalten hinzufügen? – edze

+0

auf welchen sollte ich einen Index hinzufügen? Auf alles? Beachten Sie auch, dass einige andere Felder durchsucht werden (ich habe einen Index für diese). – Nin

+2

Ja, ein geordneter Index für jede Spalte, die Sie gruppieren müssen. Wenn Sie nach 'a' gruppieren, beginnt MySQL damit, Ihre Tabelle nach' a' zu sortieren und so weiter. Ich denke, das ist dein Engpass. – edze

Antwort

2

Vielleicht wird so etwas schneller funktionieren.

select qq, q, count(*) from 
(
select 'a' qq, a q FROM test 
union all select 'b' qq, b q FROM test 
union all select 'c' qq, c q FROM test 
union all select 'd' qq, d q FROM test 
union all select 'e' qq, e q FROM test 
) t 
group by qq, q; 
+0

Leistung ist das gleiche – Nin

3
select 'a' as `column`, a as data, count(*) 
FROM test 
group by 'a', a 
union 
select 'b', b, count(*) 
FROM test 
group by 'b', b 
union 
select 'c', c, count(*) 
FROM test 
group by 'c', c 
union 
select 'd', d, count(*) 
FROM test 
group by 'd', d 
union 
select 'e', e, count(*) 
FROM test 
group by 'e', e 

Sie wissen nicht, ob es besser ist, aber zumindest wird der Planer eine Chance, es zu optimieren hat.

+0

Dies funktioniert fast genauso wie das Original (tatsächlich etwas langsamer). – Nin

1

EDIT: Diese Antwort ist völlig aus der Bahn

Versuchen Sie, die folgenden; es ist eine saubere Abfrage, mit nur einem Durchgang, aber ich bin nicht sicher, wie gut es aufgrund der DISTINCT durchführen wird:

SELECT 
    COUNT(DISTINCT a) AS a, 
    COUNT(DISTINCT b) AS b, 
    COUNT(DISTINCT c) AS c, 
    COUNT(DISTINCT d) AS d, 
FROM 
    t 
; 
+0

aber das wird mir nur die Anzahl der verschiedenen Elemente, nicht den Wert dieser Elemente mit seinen zählt. – Nin

+0

Whoops. Mein Fehler; komplett aus der Spur –

0

nichts original, aber man konnte versuchen diese.

SELECT t.col, t.val, t.c FROM 
(
    SELECT 'a' col, a val, count(*) c FROM test GROUP BY a 
    UNION ALL 
    SELECT 'b' col, b val, count(*) c FROM test GROUP BY b 
    UNION ALL 
    SELECT 'c' col, c val, count(*) c FROM test GROUP BY c 
    UNION ALL 
    SELECT 'd' col, d val, count(*) c FROM test GROUP BY d 
    UNION ALL 
    SELECT 'e' col, e val, count(*) c FROM test GROUP BY e 
) t 

Aber wenn Performance-Problem hier ist, würde Ich mag die gleiche Sache @edze vorschlagen vorgeschlagen - Index für die Spalten (ja alle 30). Es wird Platz kosten, aber die Leistung steigern. Oder erstellen Sie View-Tabelle

für diese Aufgabe und dann einfach tun, wenn es oft ausgeführt wird.

0

Abhängig von der Ökologie hier könnte es effizienter sein, eine Tabelle von Aggregatdaten einmal zu erstellen und dann immer auf dem neuesten Stand zu halten, wenn diese Tabelle geändert wird. Ihre aggregierte Datentabelle würde eine Zeile für jeden (aktuellen) Wert und dann 30 zusätzliche Spalten mit Zählwerten haben. Dann können Sie Trigger auf das Original setzen, die die Zählungen aktualisieren. Das verlangsamt natürlich die Schreiboperationen für die Originaltabelle, fügt aber 30 Indizes hinzu.

+0

Das Hinzufügen eines Indexes für eine Spalte mit nur 5 verschiedenen Werten hilft nicht, da MySQL diesen Index wahrscheinlich ignoriert. Eine aggregierte Tabelle klingt gut, aber in diesem Fall wähle ich bereits eine Teilmenge dieser Tabelle basierend auf einigen Spalten, so dass eine aggregierte Tabelle in diesem Fall nicht ausgeführt werden kann. – Nin