Проблема производительности oracle при подсчете()
Я использую Oracle 11g, основная таблица имеет около 10M записей. Вот мой вопрос:
SELECT COUNT (*)
FROM CONTACT c INNER JOIN STATUS S ON C.STATUS = S.STATUS
WHERE C.USER = 1 AND S.REQUIRE = 1 AND ROWNUM = 1;
стоимость 3736, но когда я изменил его на эту форму:
SELECT COUNT (*) FROM
(SELECT 1 FROM CONTACT c INNER JOIN STATUS S ON C.STATUS = S.STATUS
WHERE C.USER = 1 AND S.REQUIRE = 1 AND ROWNUM = 1);
стоимость стала 5! В чем разница между этими 2 запросами?
вот план объяснения для обоих запросов:
первый запрос:
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 10 | 3736 (1)| 00:00:45 |
| 1 | SORT AGGREGATE | | 1 | 10 | | |
|* 2 | COUNT STOPKEY | | | | | |
| 3 | NESTED LOOPS | | 4627 | 46270 | 3736 (1)| 00:00:45 |
| 4 | TABLE ACCESS BY INDEX ROWID| CONTACT | 6610 | 33050 | 3736 (1)| 00:00:45 |
|* 5 | INDEX RANGE SCAN | IX_CONTACT_USR | 6610 | | 20 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | IX_CONTACT_STATUS | 1 | 5 | 0 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(ROWNUM=1)
5 - access("C"."USER"=1)
6 - access("C"."STATUS"="S"."STATUS" AND "S"."REQUIRE"=1)
второй запрос:
-----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 5 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | | | |
| 2 | VIEW | | 1 | | 5 (0)| 00:00:01 |
|* 3 | COUNT STOPKEY | | | | | |
| 4 | NESTED LOOPS | | 2 | 20 | 5 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID| CONTACT | 3 | 15 | 5 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | IX_CONTACT_USR | 6610 | | 3 (0)| 00:00:01 |
|* 7 | INDEX RANGE SCAN | IX_CONTACT_STATUS | 1 | 5 | 0 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter(ROWNUM=1)
6 - access("C"."USER"=1)
7 - access("C"."STATUS"="S"."STATUS" AND "S"."REQUIRE"=1)
Я выполнил 2 запроса, первый иногда стоил 45s+ (например, первый запустите или измените идентификатор пользователя), иначе это будет стоить
когда я выполнил второй запрос, я всегда могу получить результат в 1s. Поэтому я думаю, что второй лучше, но я не знаю, почему он сильно улучшается.
3 ответов
вы можете увидеть, где разница приходит, сравнивая строку в планах выполнения, которые обращаются к CONTACT
таблица (смотрит на столбец строк, первый).
первый:
| 4 | TABLE ACCESS BY INDEX ROWID| CONTACT | 6610 | 33050 | 3736 (1)| 00:00:45 |
второй:
| 5 | TABLE ACCESS BY INDEX ROWID| CONTACT | 3 | 15 | 5 (0)| 00:00:01 |
в первом примере ROWNUM = 1
предикат не применяется до тех пор, пока CONTACT
таблица была доступна, так что вы получаете 6610
строки, возвращенные из этой таблицы. В то время как во втором оптимизаторе запросов возвращается только 3
. Это на много порядков меньше, поэтому вы видите, что второй запрос выполняется быстрее.
что касается того, почему второе выполнение "медленного" запроса является "быстрым", вы думаете, что это правильно - данные были загружены с диска в буферный кэш, поэтому доступ намного быстрее.
скорее всего, это просто разница в оценке, и у них будет одинаковая статистика выполнения. Трассировка обоих + tkprof для получения реальных данных. Также, если вы хотите получить более подробную информацию о логике оптимизатора-сделайте жесткий анализ с событием 10053.
стоимость - это не только фактор для запросов, иногда это зависит от сервера, который u R показывает, что это стоимость процессора или стоимость ввода-вывода, несколько раз стоимость моя варьируется из-за мощности столбца, условий запроса. если вы хотите увидеть много разъяснений по запросам, получите план объяснения или TKPROOF, чтобы вы узнали , что он собирается для полного сканирования таблицы или какой индекс собирает и время выполнения.