Как предложение IN влияет на производительность в Oracle? - PullRequest
7 голосов
/ 10 февраля 2011
UPDATE table1 
       SET col1 = 'Y'
     WHERE col2 in (select col2 from table2)

В приведенном выше запросе представьте, что внутренний запрос возвращает 10000 строк.Влияет ли этот запрос с предложением IN на производительность?

Если это так, что можно сделать для более быстрого выполнения?

Ответы [ 3 ]

11 голосов
/ 10 февраля 2011

, если подзапрос возвращает большое количество строк по сравнению с количеством строк в TABLE1, оптимизатор, вероятно, создаст план, подобный следующему:

--------------------------------------------------------------------------------
| Id  | Operation           | Name   | Rows  | Bytes |TempSpc| Cost (%CPU)| Time
--------------------------------------------------------------------------------
|   0 | UPDATE STATEMENT    |        |   300K|    24M|       |  1581   (1)| 00:0
|   1 |  UPDATE             | TABLE1 |       |       |       |            |
|*  2 |   HASH JOIN SEMI    |        |   300K|    24M|  9384K|  1581   (1)| 00:0
|   3 |    TABLE ACCESS FULL| TABLE1 |   300K|  5860K|       |   355   (2)| 00:0
|   4 |    TABLE ACCESS FULL| TABLE2 |   168K|    10M|       |   144   (2)| 00:0
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("COL2"="COL2")

Он будет сканировать обе таблицы один раз и обновлять толькостроки в TABLE1 общие для обеих таблиц.Это очень эффективный план, если вам нужно обновить много строк.

Иногда внутренний запрос будет иметь несколько строк по сравнению с количеством строк в TABLE1.Если у вас есть индекс на TABLE1(col2), вы можете получить план, подобный следующему:

-------------------------------------------------------------------------------
| Id  | Operation            | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | UPDATE STATEMENT     |        |    93 |  4557 |   247   (1)| 00:00:03 |
|   1 |  UPDATE              | TABLE1 |       |       |            |          |
|   2 |   NESTED LOOPS       |        |    93 |  4557 |   247   (1)| 00:00:03 |
|   3 |    SORT UNIQUE       |        |    51 |  1326 |   142   (0)| 00:00:02 |
|   4 |     TABLE ACCESS FULL| TABLE2 |    51 |  1326 |   142   (0)| 00:00:02 |
|*  5 |    INDEX RANGE SCAN  | IDX1   |     2 |    46 |     2   (0)| 00:00:01 |
-------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   5 - access("T1"."COL2"="T2"."COL2")

В этом случае Oracle будет читать строки из TABLE2 и для каждой (уникальной) строки выполнитьдоступ к индексу в TABLE1.

Какой доступ быстрее, зависит от избирательности внутреннего запроса и кластеризации индекса в TABLE1 (строки с аналогичным значением col2 в TABLE1 рядом друг с другом или случайным образомвыкладывать?).В любом случае, с точки зрения производительности, если вам нужно выполнить это обновление, этот запрос является одним из самых быстрых способов сделать это.

3 голосов
/ 10 февраля 2011
UPDATE table1 outer
   SET col1 = 'Y'
 WHERE EXISTS (select null
                 from table2
                WHERE col2 = outer.col2)

Это может быть лучше

Чтобы понять, что лучше, посмотрите план выполнения.

2 голосов
/ 11 февраля 2011

Из Oracle:

11.5.3.4 Использование EXISTS и IN для подзапросов

При определенных обстоятельствах лучше использовать IN, а не EXISTS. В Вообще, если избирательный предикат в подзапросе, затем используйте IN. Если селективный предикат в родительском запрос, затем используйте EXISTS.

Из моего опыта я видел лучшие планы, использующие EXISTS, где подзапрос возвращает большое количество строк.

См. здесь для получения дополнительной информации о Oracle

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...