Gran diferencia de rendimiento cuando se usa grupo por versus distinto


81

Estoy realizando algunas pruebas en un HSQLDBservidor con una tabla que contiene 500 000 entradas. La tabla no tiene índices. Hay 5000 claves comerciales distintas. Necesito una lista de ellos. Naturalmente comencé con una DISTINCTconsulta:

SELECT DISTINCT business_key FROM memory WHERE
   concept <> 'case' or 
   attrib <> 'status' or 
   value <> 'closed'

¡¡¡Tarda unos 90 segundos !!!

Luego intenté usar GROUP BY:

SELECT business_key FROM memory WHERE
       concept <> 'case' or 
       attrib <> 'status' or 
       value <> 'closed'
GROUP BY business_key

¡¡¡Y tarda 1 segundo !!!

Intenté averiguar la diferencia que ejecuté, EXLAIN PLAN FORpero parece dar la misma información para ambas consultas.

EXLAIN PLAN FOR DISTINCT ...

isAggregated=[false]
columns=[
  COLUMN: PUBLIC.MEMORY.BUSINESS_KEY
]
[range variable 1
  join type=INNER
  table=MEMORY
  alias=M
  access=FULL SCAN
  condition = [    index=SYS_IDX_SYS_PK_10057_10058
    other condition=[
    OR arg_left=[
     OR arg_left=[
      NOT_EQUAL arg_left=[
       COLUMN: PUBLIC.MEMORY.CONCEPT] arg_right=[
       VALUE = case, TYPE = CHARACTER]] arg_right=[
      NOT_EQUAL arg_left=[
       COLUMN: PUBLIC.MEMORY.ATTRIB] arg_right=[
       VALUE = status, TYPE = CHARACTER]]] arg_right=[
     NOT_EQUAL arg_left=[
      COLUMN: PUBLIC.MEMORY.VALUE] arg_right=[
      VALUE = closed, TYPE = CHARACTER]]]
  ]
]]
PARAMETERS=[]
SUBQUERIES[]
Object References
PUBLIC.MEMORY
PUBLIC.MEMORY.CONCEPT
PUBLIC.MEMORY.ATTRIB
PUBLIC.MEMORY.VALUE
PUBLIC.MEMORY.BUSINESS_KEY
Read Locks
PUBLIC.MEMORY
WriteLocks

EXLAIN PLAN FOR SELECT ... GROUP BY ...

isDistinctSelect=[false]
isGrouped=[true]
isAggregated=[false]
columns=[
  COLUMN: PUBLIC.MEMORY.BUSINESS_KEY
]
[range variable 1
  join type=INNER
  table=MEMORY
  alias=M
  access=FULL SCAN
  condition = [    index=SYS_IDX_SYS_PK_10057_10058
    other condition=[
    OR arg_left=[
     OR arg_left=[
      NOT_EQUAL arg_left=[
       COLUMN: PUBLIC.MEMORY.CONCEPT] arg_right=[
       VALUE = case, TYPE = CHARACTER]] arg_right=[
      NOT_EQUAL arg_left=[
       COLUMN: PUBLIC.MEMORY.ATTRIB] arg_right=[
       VALUE = status, TYPE = CHARACTER]]] arg_right=[
     NOT_EQUAL arg_left=[
      COLUMN: PUBLIC.MEMORY.VALUE] arg_right=[
      VALUE = closed, TYPE = CHARACTER]]]
  ]
]]
groupColumns=[
COLUMN: PUBLIC.MEMORY.BUSINESS_KEY]
PARAMETERS=[]
SUBQUERIES[]
Object References
PUBLIC.MEMORY
PUBLIC.MEMORY.CONCEPT
PUBLIC.MEMORY.ATTRIB
PUBLIC.MEMORY.VALUE
PUBLIC.MEMORY.BUSINESS_KEY
Read Locks
PUBLIC.MEMORY
WriteLocks

EDITAR : Hice pruebas adicionales. Con 500 000 registros HSQLDBcon todas las claves comerciales distintas, el rendimiento de DISTINCTahora es mejor: 3 segundos, en comparación con lo GROUP BYque tomó alrededor de 9 segundos.

En MySQLambas consultas se realiza lo mismo:

MySQL: 500 000 filas - 5 000 claves comerciales distintas: ambas consultas: 0,5 segundos MySQL: 500 000 filas - todas las claves comerciales distintas: SELECT DISTINCT ...- 11 segundos SELECT ... GROUP BY business_key- 13 segundos

Entonces el problema solo está relacionado con HSQLDB.

Estaré muy agradecido si alguien me puede explicar por qué hay una diferencia tan drástica.


2
muestre el resultado de EXPLAIN PLANY intente ejecutar la DISTINCTconsulta DESPUÉS de ejecutar el GROUP BYpara ver si quizás algo de almacenamiento en caché está sesgando el tiempo ...
Yahia

Dado que obtiene el mismo plan para cada consulta, parece que los datos de la tabla o el resultado se han almacenado en caché.
2011

Los ejecuté tantas veces que creo que el almacenamiento en caché no es un problema. Estoy publicando la EXLAIN PLAN FORsalida.
Martin Dimitrov

Tengo una idea, pero realmente no estoy seguro, inténtelo SELECT DISTINCT business_key FROM (SELECT business_key FROM memory WHERE concept <> 'case' or attrib <> 'status' or value <> 'closed'), esto debería mostrar el mismo rendimiento que ve con el GROUP BYSI mi idea es correcta.
Yahia

@Yahia: todavía muy lento - 94 segundos. Ejecutaré las mismas consultas en MySQL para ver qué se muestra
Martin Dimitrov

Respuestas:


77

Las dos consultas expresan la misma pregunta. Aparentemente, el optimizador de consultas elige dos planes de ejecución diferentes. Mi conjetura sería que el distinctenfoque se ejecuta como:

  • Copiar todos los business_keyvalores a una tabla temporal
  • Ordenar la tabla temporal
  • Escanee la tabla temporal, devolviendo cada elemento que sea diferente al anterior

El group bypodría ejecutarse como:

  • Escanee la tabla completa, almacenando cada valor de business keyen una tabla hash
  • Devuelve las claves de la tabla hash

El primer método se optimiza para el uso de la memoria: aún funcionaría razonablemente bien cuando parte de la tabla temporal debe intercambiarse. El segundo método optimiza la velocidad, pero potencialmente requiere una gran cantidad de memoria si hay muchas claves diferentes.

Dado que tiene suficiente memoria o pocas claves diferentes, el segundo método supera al primero. No es inusual ver diferencias de rendimiento de 10x o incluso 100x entre dos planes de ejecución.


Gracias por la respuesta. ¿Son evidentes sus conjeturas a partir del EXPLAINresultado? Ambos me parecen iguales.
Martin Dimitrov

Por lo que puedo ver, el plan no especifica cómo ejecutará la combinación. Ni siquiera estoy seguro de por qué ejecutaría una combinación. Probablemente sea necesario un especialista en HSQLDB para leer el resultado de la explicación.
Andomar

Como indica la respuesta, el segundo método usa más memoria y puede afectar la recolección de basura (GC) con demasiada frecuencia. Si aumenta la asignación de memoria JVM, no debería haber una gran diferencia entre los dos tiempos de consulta.
fredt

Hice una prueba adicional ingresando todas las claves distintas en la tabla (ver arriba). ¿Crees que el resultado prueba tu punto? Muchas gracias.
Martin Dimitrov

2
¿Puede un experto en PYME explicar esto con más detalle con ejemplos? He tenido este problema muchas veces pero parece que no puedo solucionarlo ... Conozco la solución, pero quiero saber cómo y POR QUÉ
singhswat
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.