Недавно я встречал такой запрос повсюду на сайте клиента:
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
 | 
DECLARE  v_var NUMBER(10);BEGIN  SELECT COUNT(*)  INTO   v_var  FROM   table1  JOIN   table2 ON table1.t1_id = table2.t1_id  JOIN   table3 ON table2.t2_id = table3.t2_id  ...  WHERE  some_predicate;  IF (v_var = 1) THEN    do_something  ELSE    do_something_else  END IF;END; | 
 К сожалению, COUNT(*) часто является первым решением, которое приходит на ум, когда мы хотим проверить наши отношения на наличие предиката.  Но COUNT() стоит дорого, особенно если все, что мы делаем, это проверяем наши отношения на существование .  Слово звонит в колокол?  Да, мы должны использовать предикат EXISTS , потому что, если нам не важно точное количество записей, которые возвращают true для данного предиката, нам не следует просматривать полный набор данных, чтобы фактически подсчитать точное число .  Приведенный выше блок PL / SQL можно переписать тривиально в этот: 
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
 | 
DECLARE  v_var NUMBER(10);BEGIN  SELECT CASE WHEN EXISTS (    SELECT 1    FROM   table1    JOIN   table2 ON table1.t1_id = table2.t1_id    JOIN   table3 ON table2.t2_id = table3.t2_id    ...    WHERE  some_predicate  ) THEN 1 ELSE 0 END  INTO   v_var  FROM   dual;  IF (v_var = 1) THEN    do_something  ELSE    do_something_else  END IF;END; | 
Давайте измерим!
Запрос 1 дает этот план выполнения:
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
 | 
-----------------------------------------------| Id  | Operation           | E-Rows | A-Rows |-----------------------------------------------|   0 | SELECT STATEMENT    |        |      1 ||   1 |  SORT AGGREGATE     |      1 |      1 ||*  2 |   HASH JOIN         |      4 |      4 ||*  3 |    TABLE ACCESS FULL|      2 |      2 ||*  4 |    TABLE ACCESS FULL|      6 |      6 |----------------------------------------------- | 
Запрос 2 дает этот план выполнения:
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
 | 
----------------------------------------------| Id  | Operation          | E-Rows | A-Rows |----------------------------------------------|   0 | SELECT STATEMENT   |        |      1 ||   1 |  NESTED LOOPS      |      4 |      1 ||*  2 |   TABLE ACCESS FULL|      2 |      1 ||*  3 |   TABLE ACCESS FULL|      2 |      1 ||   4 |  FAST DUAL         |      1 |      1 |---------------------------------------------- | 
  Вы можете игнорировать операции TABLE ACCESS FULL , фактический запрос был выполнен в тривиальной базе данных без индексов. 
  Однако важны значительно улучшенные значения E-Rows (E = Estimated) и, что еще важнее, оптимальные значения A-Rows (A = Actual).  Как вы можете видеть, предикат EXISTS может быть прерван рано, как только будет обнаружена первая запись, соответствующая предикату — в этом случае немедленно. 
Смотрите этот пост о более подробной информации о том, как собирать планы выполнения Oracle.
Вывод
  Всякий раз, когда вы сталкиваетесь с операцией COUNT(*) , вы должны спросить себя, действительно ли она нужна.  Вы действительно должны знать точное количество записей, которые соответствуют предикату?  Или вы уже счастливы, зная, что любая запись соответствует предикату? 
Ответ: это, вероятно, последний.
| Ссылка: | Совет дня по SQL: Остерегайтесь SELECT COUNT (*) от нашего партнера по JCG Лукаса Эдера в блоге JAVA, SQL и AND JOOQ . |