2012-02-14 8 views
10

Obtuve un rendimiento deficiente de DISTINCT. El plan de explicación indica que está haciendo SORT (GROUP BY) que no suena bien. Esperaría algún tipo de agregación HASH para producir un resultado mucho mejor. ¿Hay alguna pista para decirle a Oracle que use HASH para DISTINCT en lugar de ordenar? He usado/* + USE_HASH_AGGREGATION */en situaciones similares, pero no funciona para DISTINCT.oracle distinct doing sort

Así que este es mi búsqueda original:

SELECT 
count(distinct userid) n, col 
FROM users 
GROUP BY col; 

usuarios tiene filas 30M, cada identificador de usuario es allí 12 veces. Esta consulta toma 70 segundos.

Ahora volvemos a escribir como

SELECT 
count(userid) n, col 
FROM 
(SELECT distinct userid, col FROM users) 
GROUP BY col 

y se tarda 40 segundos. Ahora agregue la pista para hacer picadillo en lugar de ordenar:

SELECT 
count(userid) n, col 
FROM 
(SELECT /*+ USE_HASH_AGGREGATION */ distinct userid, col FROM users) 
GROUP BY col 

y se tarda 10 segundos.

Si alguien puede explicarme por qué sucede esto o cómo puedo superar la primera consulta simple para trabajar tan bien como la tercera, sería fantástico.
La razón por la que me importa la simplicidad de la consulta es porque realmente se generan estas consultas.

Planes: 1) lentas:

---------------------------------------------------------------------------------------------------------------------------------------------------- 
| Id | Operation  | Name   | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | OMem | 1Mem | Used-Mem | Used-Tmp| 
-------------------------------------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT |    |  1 |  |  5 |00:01:12.01 |  283K| 292K|  |  |  |  | 
| 1 | SORT GROUP BY  |    |  1 |  5 |  5 |00:01:12.01 |  283K| 292K| 194M| 448K| 172M (0)| 73728 | 
| 2 | TABLE ACCESS FULL| USERS |  1 |  29M|  29M|00:00:08.17 |  283K| 283K|  |  |  |  | 

2) Fast

-------------------------------------------------------------------------------------------------------------------------------------------- 
| Id | Operation  | Name   | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | OMem | 1Mem | Used-Mem | 
-------------------------------------------------------------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT  |    |  1 |  |  5 |00:00:13.09 |  283K| 283K| | |  | 
| 1 | SORT GROUP BY  |    |  1 |  5 |  5 |00:00:13.09 |  283K| 283K| 3072 | 3072 | 2048 (0)| 
| 2 | VIEW    |    |  1 | 8647K| 2445K|00:00:13.16 |  283K| 283K| | |  | 
| 3 | HASH UNIQUE  |    |  1 | 8647K| 2445K|00:00:12.57 |  283K| 283K| 113M| 10M| 216M (0)| 
| 4 |  TABLE ACCESS FULL| USERS   |  1 |  29M|  29M|00:00:07.68 |  283K| 283K| | |  | 
-------------------------------------------------------------------------------------------------------------------------------------------- 
+1

+1: Buen lugar, buen trabajo y buena suerte. También estoy intrigado por este. – MatBailie

+0

¿Podría mostrar los planes de explicación/ejecución para cada una de las consultas? Además, uno debe tener en cuenta que la pista 'USE_HASH_AGGREGATION' está oficialmente indocumentada. –

+0

Publicación cruzada desde [dba.se]: http://dba.stackexchange.com/questions/13028 –

Respuesta

2

¿Qué tal intentar lo siguiente: Si tuviera un índice en col y identificador de usuario debe resolver por completo en el índice y no es necesario tocar la tabla en absoluto.

Select count(userid) n, col 
from (select col, userid from users group by col, userid) 
group by col 
; 
+0

ayuda si la tabla es muy amplia, pero mis números son para la tabla estrecha, por lo que el índice no ayuda. –