2012-02-14 3 views
10

Я получаю плохую работу от DISTINCT. План объяснения показывает, что он выполняет SORT (GROUP BY), который звучит неправильно. Я ожидал бы, что какая-то агрегация HASH даст гораздо лучший результат. Есть ли намек на то, чтобы сказать оракулу использовать HASH для DISTINCT, а не сортировать? Я использовал/* + USE_HASH_AGGREGATION */в аналогичных ситуациях, но он не работает для DISTINCT.oracle different do sort

Так что это мой оригинальный запрос:

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

пользователи имеют 30M строк, каждая идент там 12 раз. Этот запрос занимает 70 секунд.

Теперь мы перепишем его в виде

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

И это занимает 40 секунд. Теперь добавьте подсказку, чтобы сделать хэш вместо вида:

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

и занимает 10 секунд.

Если кто-нибудь может объяснить мне, почему это происходит, или как я могу победить первый простой запрос в работе так же хорошо, как и третий, это было бы фантастическим.
Причина, по которой я забочусь о простоте запроса, заключается в том, что эти запросы фактически генерируются.

Чертеж: 1) Медленный:

---------------------------------------------------------------------------------------------------------------------------------------------------- 
| 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) Быстрый

-------------------------------------------------------------------------------------------------------------------------------------------- 
| 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: Хорошее место, хорошая работа и удача. Я тоже заинтригован этим. – MatBailie

+0

Не могли бы вы показать планы объяснения/исполнения для каждого из запросов? Кроме того, следует отметить, что подсказка 'USE_HASH_AGGREGATION' официально недокументирована. –

+0

Перекрестная рассылка с [dba.se]: http://dba.stackexchange.com/questions/13028 –

ответ

2

Как о попытке следующее: Если вы имели индекс на седловине и USERID она должна полностью решить в индекс и не нужно прикасаться к таблице вообще.

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

index помогает, если таблица очень широкая, но мои номера для узкой таблицы, поэтому индекс не помогает. –

Смежные вопросы