2010-03-17 16 views
7

Leí en el Manual de referencia de MySQL y descubrí que cuando puede usar el índice, simplemente realiza un escaneo de índice, otro crea tablas tmp y hace cosas como filesort. Y también leí en otro artículo que el resultado "Agrupar por" ordenará por grupo por columnas de forma predeterminada, si se agrega la cláusula "ordenar por nulo", no se agregará el archivo. La diferencia se puede encontrar en la cláusula "explicar ...". así que mi problema es: ¿cuál es la diferencia entre la cláusula "agrupar por" que con "ordenar por nulo" y que no tiene? intento utilizar perfiles para ver qué mysql lo hacen en el fondo, y sólo ver el resultado como:¿Cómo implementa MySQL el "grupo por"?

result for group clause without order by null: 
|preparing      | 0.000016 | 
| Creating tmp table    | 0.000048 | 
| executing      | 0.000009 | 
| Copying to tmp table   | 0.000109 | 
**| Sorting result     | 0.000023 |** 
| Sending data     | 0.000027 | 

result for clause with "order by null": 
preparing      | 0.000016 | 
| Creating tmp table    | 0.000052 | 
| executing      | 0.000009 | 
| Copying to tmp table   | 0.000114 | 
| Sending data     | 0.000028 | 

Así que supongo que lo MySQL hacer cuando el "orden por nula", agregó, que no utiliza el algoritmo filesort , tal vez cuando crea la tabla tmp, también utiliza el índice y luego utiliza el índice para hacer el grupo por operación, cuando se completa, simplemente lee el resultado de las filas de la tabla y no ordena el resultado.

Pero mi opinión original es que MySQL puede usar quicksort para ordenar los elementos y luego agruparlos, por lo que también se ordenará el resultado.

Cualquier opinión apreciada, gracias.

Respuesta

-1

Agrupar por está agrupando registro por alguna columna. Por ejemplo, tiene la columna "clase" y puede agrupar esta columna para que obtenga registros agrupados según los valores de esta columna.

1
mysql> select max(post_date),post_author from wp_posts 
-> where id > 10 and id < 1000 
-> group by post_author; 
+———————+————-+ 
| max(post_date) | post_author | 
+———————+————-+ 
| 2009-07-03 12:58:39 | 1 | 
+———————+————-+ 
1 row in set (0.01 sec) 

mysql> show profiles; 
+———-+————+————————+ 
| Query_ID | Duration | Query | 
+———-+————+————————+ 
| 1 | 0.00013200 | SELECT DATABASE() | 
| 2 | 0.00030900 | show databases | 
| 3 | 0.00030400 | show tables | 
| 4 | 0.01180000 | select max(post_date),post_author from wp_posts where id > 10 and id < 1000 group by post_author |4 rows in set (0.00 sec) 

mysql> show profile cpu,block io for query 4; 
+———————-+———-+———-+————+————–+—————+ 
| Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out | 
+———————-+———-+———-+————+————–+—————+ 
| starting | 0.000085 | 0.000000 | 0.000000 | 0 | 0 | 
| Opening tables | 0.000010 | 0.000000 | 0.000000 | 0 | 0 | 
| System lock | 0.000005 | 0.000000 | 0.000000 | 0 | 0 | 
| Table lock | 0.000008 | 0.000000 | 0.000000 | 0 | 0 | 
| init | 0.000029 | 0.000000 | 0.000000 | 0 | 0 | 
| optimizing | 0.000014 | 0.000000 | 0.000000 | 0 | 0 | 
| statistics | 0.000062 | 0.000000 | 0.000000 | 0 | 0 | 
| preparing | 0.000016 | 0.000000 | 0.000000 | 0 | 0 | 
| Creating tmp table | 0.000035 | 0.000000 | 0.000000 | 0 | 0 | 
| executing | 0.000004 | 0.000000 | 0.000000 | 0 | 0 | 
| Copying to tmp table | 0.011386 | 0.004999 | 0.006999 | 0 | 0 | 
| Sorting result | 0.000044 | 0.000000 | 0.000000 | 0 | 0 | 
| Sending data | 0.000036 | 0.000000 | 0.000000 | 0 | 0 | 
| end | 0.000004 | 0.000000 | 0.000000 | 0 | 0 | 
| removing tmp table | 0.000012 | 0.000000 | 0.000000 | 0 | 0 | 
| end | 0.000004 | 0.000000 | 0.000000 | 0 | 0 | 
| end | 0.000004 | 0.000000 | 0.000000 | 0 | 0 | 
| query end | 0.000004 | 0.000000 | 0.000000 | 0 | 0 | 
| freeing items | 0.000013 | 0.000000 | 0.000000 | 0 | 0 | 
| closing tables | 0.000018 | 0.000000 | 0.000000 | 0 | 0 | 
| logging slow query | 0.000003 | 0.000000 | 0.000000 | 0 | 0 | 
| cleaning up | 0.000004 | 0.000000 | 0.000000 | 0 | 0 | 
+———————-+———-+———-+————+————–+—————+ 
22 rows in set (0.00 sec) 

mysql> 
mysql> 
mysql> select max(post_date),post_author from wp_posts 
-> where id > 10 and id < 1000 
-> group by post_author order by null; 
+———————+————-+ 
| max(post_date) | post_author | 
+———————+————-+ 
| 2009-07-03 12:58:39 | 1 | 
+———————+————-+ 
1 row in set (0.01 sec) 

mysql> show profiles; 
+———-+————+—————–+ 
| Query_ID | Duration | Query 
+———-+————+—————–+ 
|1 | 0.00013200 | SELECT DATABASE() 
|2 | 0.00030900 | show databases 
|3 | 0.00030400 | show tables 
|4 | 0.01180000 | select max(post_date),post_author from wp_posts where id > 10 and id < 1000 group by post_author 
|5 | 0.01177700 | select max(post_date),post_author from wp_posts where id > 10 and id < 1000 group by post_author order by null 
5 rows in set (0.00 sec) 
mysql> show profile cpu,block io for query 5; 
+———————-+———-+———-+————+————–+—————+ 
| Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out | 
+———————-+———-+———-+————+————–+—————+ 
| starting | 0.000097 | 0.000000 | 0.000000 | 0 | 0 | 
| Opening tables | 0.000013 | 0.000000 | 0.000000 | 0 | 0 | 
| System lock | 0.000006 | 0.000000 | 0.000000 | 0 | 0 | 
| Table lock | 0.000008 | 0.000000 | 0.000000 | 0 | 0 | 
| init | 0.000032 | 0.000000 | 0.000000 | 0 | 0 | 
| optimizing | 0.000012 | 0.000000 | 0.000000 | 0 | 0 | 
| statistics | 0.000065 | 0.000000 | 0.000000 | 0 | 0 | 
| preparing | 0.000017 | 0.000000 | 0.000000 | 0 | 0 | 
| Creating tmp table | 0.000040 | 0.000000 | 0.000000 | 0 | 0 | 
| executing | 0.000003 | 0.000000 | 0.000000 | 0 | 0 | 
| Copying to tmp table | 0.011369 | 0.005999 | 0.004999 | 0 | 0 | 
| Sending data | 0.000040 | 0.000000 | 0.000000 | 0 | 0 | 
| end | 0.000004 | 0.000000 | 0.000000 | 0 | 0 | 
| removing tmp table | 0.000031 | 0.000000 | 0.000000 | 0 | 0 | 
| end | 0.000005 | 0.000000 | 0.000000 | 0 | 0 | 
| end | 0.000004 | 0.000000 | 0.000000 | 0 | 0 | 
| query end | 0.000004 | 0.000000 | 0.000000 | 0 | 0 | 
| freeing items | 0.000012 | 0.000000 | 0.000000 | 0 | 0 | 
| closing tables | 0.000009 | 0.000000 | 0.000000 | 0 | 0 | 
| logging slow query | 0.000003 | 0.000000 | 0.000000 | 0 | 0 | 
| cleaning up | 0.000003 | 0.000000 | 0.000000 | 0 | 0 | 
+———————-+———-+———-+————+————–+—————+ 
21 rows in set (0.00 sec) 

Desde aquí podemos ver que la segunda parte does't tener la "Clasificación de resultado" paso, por lo que un poco impacto en el rendimiento.

+0

bueno, lo he mencionado anteriormente. lo que realmente quiero saber es lo que hace mysql para realizar la acción "agrupar por". – user188916

1

La cláusula GROUP BY permite un modificador WITH ROLLUP que provoca que se agreguen filas adicionales al resultado del resumen. Estas filas representan operaciones de resumen de nivel superior (o superagregado). ROLLUP le permite responder preguntas en múltiples niveles de análisis con una sola consulta. Se puede usar, por ejemplo, para proporcionar soporte para operaciones OLAP (Online Analytical Processing).

Supongamos que una tabla llamada de ventas tiene años, países, productos y columnas de beneficio para la rentabilidad de las ventas de grabación:

CREATE TABLE sales ( años INT NOT NULL, país VARCHAR (20) NOT NULL, producto VARCHAR (32) NOT NULL, beneficio INT );

contenido de la tabla se puede resumir por año, con un simple GROUP BY como esto:

mysql> SELECT años, SUM (ganancia) del grupo de ventas por año; + ------ + ------------- + | año | SUM (beneficio) | + ------ + ------------- + | 2000 | 4525 | | 2001 | 3010 | + ------ + ------------- +

Este resultado muestra el beneficio total de cada año, pero si también desea determinar el beneficio total sumado sobre todos años, debe sumar los valores individuales o ejecutar una consulta adicional.

O puede usar ROLLUP, que proporciona ambos niveles de análisis con una sola consulta.Agregar un modificador WITH ROLLUP a la cláusula GROUP BY hace que la consulta produzca otra fila que muestre el total general en todos los valores del año:

mysql> SELECT año, SUM (beneficio) FROM ventas GRUPO POR año WITH ROLLUP; + ------ + ------------- + | año | SUM (beneficio) | + ------ + ------------- + | 2000 | 4525 | | 2001 | 3010 | | NULL | 7535 | + ------ + ------------- +

La gran línea total de agregado se identifica por el valor NULL en la columna del año.

ROLLUP tiene un efecto más complejo cuando hay varias columnas GROUP BY. En este caso, cada vez que hay un "corte" (cambio en el valor) en cualquier columna de agrupación excepto en la última, la consulta produce una fila de resumen extra-agregado adicional.

Por ejemplo, sin ROLLUP, un resumen en la tabla de ventas basado en el año, el país y el producto podría tener este aspecto:

mysql> SELECT year, país, producto, SUM (ganancia) -> DE ventas -> GRUPO POR año, país, producto; + ------ + --------- + ------------ + ------------- + | año | país | producto | SUM (beneficio) | + ------ + --------- + ------------ + ------------- + | 2000 | Finlandia | Computadora | 1500 | | 2000 | Finlandia | Teléfono | 100 | | 2000 | India | Calculadora | 150 | | 2000 | India | Computadora | 1200 | | 2000 | Estados Unidos | Calculadora | 75 | | 2000 | Estados Unidos | Computadora | 1500 | | 2001 | Finlandia | Teléfono | 10 | | 2001 | Estados Unidos | Calculadora | 50 | | 2001 | Estados Unidos | Computadora | 2700 | | 2001 | Estados Unidos | TV | 250 | + ------ + --------- + ------------ + ------------- +

El resultado indica valores de resumen solo al nivel de análisis del año/país/producto.Cuando se añade ROLLUP, la consulta produce varias filas adicionales:

mysql> SELECT años, el país, producto, SUM (Profit) -> de las ventas -> GRUPO POR año, país, producto con ROLLUP; + ------ + --------- + ------------ + ------------- + | año | país | producto | SUM (beneficio) | + ------ + --------- + ------------ + ------------- + | 2000 | Finlandia | Computadora | 1500 | | 2000 | Finlandia | Teléfono | 100 | | 2000 | Finlandia | NULL | 1600 | | 2000 | India | Calculadora | 150 | | 2000 | India | Computadora | 1200 | | 2000 | India | NULL | 1350 | | 2000 | Estados Unidos | Calculadora | 75 | | 2000 | Estados Unidos | Computadora | 1500 | | 2000 | Estados Unidos | NULL | 1575 | | 2000 | NULL | NULL | 4525 | | 2001 | Finlandia | Teléfono | 10 | | 2001 | Finlandia | NULL | 10 | | 2001 | Estados Unidos | Calculadora | 50 | | 2001 | Estados Unidos | Computadora | 2700 | | 2001 | Estados Unidos | TV | 250 | | 2001 | Estados Unidos | NULL | 3000 | | 2001 | NULL | NULL | 3010 | | NULL | NULL | NULL | 7535 | + ------ + --------- + ------------ + ------------- +

Para esta consulta, al agregar ROLLUP, el resultado incluye información de resumen en cuatro niveles de análisis, no solo uno. Aquí es cómo interpretar la salida de ROLLUP:

* 

    Following each set of product rows for a given year and country, an extra summary row is produced showing the total for all products. These rows have the product column set to NULL. 
* 

    Following each set of rows for a given year, an extra summary row is produced showing the total for all countries and products. These rows have the country and products columns set to NULL. 
* 

    Finally, following all other rows, an extra summary row is produced showing the grand total for all years, countries, and products. This row has the year, country, and products columns set to NULL. 

Otras consideraciones Cuando se utiliza ROLLUP

La siguiente lista de algunos comportamientos específicos para la implementación de MySQL de ROLLUP:

Cuando se utiliza ROLLUP, no se puede también use una cláusula ORDER BY para ordenar los resultados. En otras palabras, ROLLUP y ORDER BY son mutuamente excluyentes. Sin embargo, todavía tienes cierto control sobre el orden de clasificación. GROUP BY en MySQL ordena los resultados, y puede usar palabras clave explícitas ASC y DESC con columnas nombradas en la lista GROUP BY para especificar el orden de clasificación para columnas individuales. (Las filas de resumen de nivel superior agregadas por ROLLUP aún aparecen después de las filas desde las que se calculan, independientemente del orden de clasificación.)

LIMIT se puede usar para restringir el número de filas devueltas al cliente. LIMIT se aplica después de ROLLUP, por lo que el límite se aplica a las filas adicionales agregadas por ROLLUP. Por ejemplo:

mysql> SELECT año, país, producto, SUM (ganancia) -> de las ventas -> GRUPO POR año, país, producto con ROLLUP -> LÍMITE 5; + ------ + --------- + ------------ + ------------- + | año | país | producto | SUM (beneficio) | + ------ + --------- + ------------ + ------------- + | 2000 | Finlandia | Computadora | 1500 | | 2000 | Finlandia | Teléfono | 100 | | 2000 | Finlandia | NULL | 1600 | | 2000 | India | Calculadora | 150 | | 2000 | India | Computadora | 1200 | + ------ + --------- + ------------ + ------------- +

El uso de LIMIT con ROLLUP puede producir resultados que son más difíciles de interpretar, ya que tiene menos contexto para comprender las filas de súper agregado.

Los indicadores NULL en cada fila de súper agregado se producen cuando la fila se envía al cliente. El servidor mira las columnas nombradas en la cláusula GROUP BY siguiendo la más a la izquierda que ha cambiado el valor. Para cualquier columna en el conjunto de resultados con un nombre que sea una coincidencia léxica con cualquiera de esos nombres, su valor se establece en NULL. (Si especifica columnas de agrupamiento por número de columna, el servidor identifica qué columnas establecer en NULL por número.)

Porque los valores NULL en las filas de super agregado se colocan en el conjunto de resultados en una etapa tan avanzada de la consulta procesamiento, no puede probarlos como valores NULL dentro de la consulta en sí. Por ejemplo, no puede agregar HAVING product IS NULL a la consulta para eliminar de la salida todas las filas, excepto las superagregadas.

Por otro lado, los valores NULL aparecen como NULL en el lado del cliente y se pueden probar como tales utilizando cualquier interfaz de programación de cliente MySQL.