2012-09-21 14 views
8

tengo una estructura de tabla como la siguiente:conseguir muchos valores agrupados de 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 
); 

Esto tiene alrededor de 30 columnas con unas columnas que tienen valores de 0-200 (a, b) y algunos sólo tienen 5 valores (0,1,2,3,4) (columna cd). Hay aprox. 120k filas en la mesa.

Para mostrar el número de elementos por fila utilizo una consulta para cada columna:

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; 

El problema con esto es que se disparará 30 consultas (una por columna) y, básicamente, va sobre el mismo conjunto de datos cada vez.

¿Hay una mejor manera de hacerlo?

He intentado con GROUP BY WITH ROLLUP, pero esto da como resultado un resultado masivo que es más lento de procesar que cada consulta individual.

Usted puede ver una selección de los datos sobre SQLfiddle: http://sqlfiddle.com/#!2/a9fd8/1

+0

Everytime 'Uso temporal; Usando filesort', ¿puede agregar índices ordenados en sus columnas? – edze

+0

en el que uno debería agregar un índice? ¿En todo? También tenga en cuenta que hay otros campos en los que se realiza una búsqueda (tengo un índice sobre ellos). – Nin

+2

Sí, un índice ordenado para cada columna que necesita agrupar. Si agrupa por 'a', entonces MySQL comenzará a ordenar su tabla por' a' y así sucesivamente. Creo que este es tu cuello de botella. – edze

Respuesta

2

Tal vez algo así funcionará más rápido.

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

el rendimiento es el mismo – 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 

No sabe si es mejor, pero al menos el planificador tendrá la oportunidad de optimizarlo.

+0

Esto realiza casi lo mismo que el original (en realidad un poco más lento). – Nin

1

EDITAR: esta respuesta es totalmente fuera de pista

Pruebe lo siguiente; se trata de una consulta más limpio, con una sola pasada, pero no estoy seguro de lo bien que llevará a cabo debido a la distintas:

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

pero eso me dará solo la cantidad de elementos diferentes, no el valor de esos elementos con sus recuentos. – Nin

+0

Whoops. Mi error; completamente fuera de la pista –

0

nada original, pero se puede probar esto.

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 

Pero si el rendimiento es cuestión aquí me gustaría sugerir lo mismo @edze sugirió - índice en columnas (sí todo 30). Costará espacio, pero aumentará el rendimiento. O incluso cree la tabla de vista

CREATE TABLE `test_view` (
    `col` char(1), 
    `value` tinyint(3), 
    `count` int 
); 

para esta tarea y luego simplemente seleccione si se realiza con frecuencia.

0

Dependiendo de la ecología aquí, podría ser más eficiente construir una tabla de datos agregados una vez y luego mantenerla actualizada siempre que se modifique esta tabla. Su tabla de datos agregados tendría una fila para cada valor (actual) y luego 30 columnas adicionales de conteos. Luego puede poner activadores en el original que actualicen los conteos. Naturalmente, eso ralentizará las operaciones de escritura en la tabla original, aunque también lo hará la adición de 30 índices.

+0

Agregar un índice en una columna con solo 5 valores distintos no ayuda, ya que MySQL probablemente ignorará ese índice. Una tabla agregada suena bien, pero en este caso ya seleccioné un subconjunto de esta tabla en función de algunas columnas, por lo que no se puede hacer una tabla agregada en este caso. – Nin

Cuestiones relacionadas