оптимизация SQL-запросов - PullRequest
5 голосов
/ 05 мая 2011

Пожалуйста, сравните следующее:

INNER JOIN table1 t1 ON t1.someID LIKE 'search.%' AND 
                        t1.someID = ( 'search.' || t0.ID )

против

INNER JOIN table1 t1 ON t1.someID = ( 'search.' || t0.ID )

Мне сказали, что первый случай оптимизирован. Но вы знаете, я не могу понять, почему это так. Насколько я понимаю, 2-й пример должен работать быстрее.

Мы используем Oracle, но, думаю, сейчас это не имеет значения.

Пожалуйста, объясните, если я не прав.

Спасибо

Ответы [ 2 ]

3 голосов
/ 05 мая 2011

Итак, вот план объяснения для запроса, который присоединяется только к объединенной строке:

SQL> explain plan for
  2     select e.* from emp e
  3         join big_table bt on bt.col2 = 'search'||trim(to_char(e.empno))
  4  /

Explained.

SQL> select * from table(dbms_xplan.display)
  2  /

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 179424166

-------------------------------------------------------------------------------
| Id  | Operation          | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |          |  1052 | 65224 |    43   (0)| 00:00:01 |
|   1 |  NESTED LOOPS      |          |  1052 | 65224 |    43   (0)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| EMP      |    20 |   780 |     3   (0)| 00:00:01 |
|*  3 |   INDEX RANGE SCAN | BIG_VC_I |    53 |  1219 |     2   (0)| 00:00:01 |
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("BT"."COL2"='search'||TRIM(TO_CHAR("E"."EMPNO")))

15 rows selected.

SQL>

Сравните и сопоставьте с планом запроса, в состав которого входит предложение LIKE:

SQL> explain plan for
  2     select e.* from emp e
  3           join big_table bt on (bt.col2 like 'search%'
  4               and bt.col2 = 'search'||trim(to_char(e.empno)))
  5  /

Explained.

SQL> select * from table(dbms_xplan.display)
  2  /

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 179424166

-------------------------------------------------------------------------------
| Id  | Operation          | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |          |     1 |    62 |     5   (0)| 00:00:01 |
|   1 |  NESTED LOOPS      |          |     1 |    62 |     5   (0)| 00:00:01 |
|*  2 |   TABLE ACCESS FULL| EMP      |     1 |    39 |     3   (0)| 00:00:01 |
|*  3 |   INDEX RANGE SCAN | BIG_VC_I |     1 |    23 |     2   (0)| 00:00:01 |
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter('search'||TRIM(TO_CHAR("E"."EMPNO")) LIKE 'search%')
   3 - access("BT"."COL2"='search'||TRIM(TO_CHAR("E"."EMPNO")))
       filter("BT"."COL2" LIKE 'search%')

17 rows selected.

SQL>

Стоимость второго запроса намного ниже, чем первого. Но это потому, что оптимизатор оценивает, что второй запрос вернет намного меньше строк , чем первый запрос. Дополнительная информация позволяет базе данных сделать более точный прогноз. (На самом деле запрос не будет возвращать строк).

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

Еще одна вещь, которую нужно иметь в виду, это то, что запрашиваемые столбцы могут повлиять на план. Эта версия выбирается из BIG_TABLE, а не EMP.

SQL> explain plan for
  2     select bt.* from emp e
  3           join big_table bt on (bt.col2 like 'search%'
  4                        and bt.col2 = 'search'||trim(to_char(e.empno)))
  5  /

Explained.

SQL> select * from table(dbms_xplan.display)
  2  /

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------------------

Plan hash value: 4042413806

------------------------------------------------------------------------------------------
| Id  | Operation                    | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |           |     1 |    46 |     4   (0)| 00:00:01 |
|   1 |  NESTED LOOPS                |           |       |       |            |          |
|   2 |   NESTED LOOPS               |           |     1 |    46 |     4   (0)| 00:00:01 |
|*  3 |    INDEX FULL SCAN           | PK_EMP    |     1 |     4 |     1   (0)| 00:00:01 |
|*  4 |    INDEX RANGE SCAN          | BIG_VC_I  |     1 |       |     2   (0)| 00:00:01 |
|   5 |   TABLE ACCESS BY INDEX ROWID| BIG_TABLE |     1 |    42 |     3   (0)| 00:00:01 |
------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - filter('search'||TRIM(TO_CHAR("E"."EMPNO")) LIKE 'search%')
   4 - access("BT"."COL2"='search'||TRIM(TO_CHAR("E"."EMPNO")))
       filter("BT"."COL2" LIKE 'search%')

19 rows selected.

SQL>
2 голосов
/ 05 мая 2011

Анализ запросов различных механизмов баз данных действительно рассказал бы историю, но мой первый инстинкт был бы в том, что первая форма фактически оптимизирована. Причина в том, что компилятор не может угадать результаты конкатенации. Он должен проделать дополнительную работу, чтобы определить значение, с которым сопоставлять данные, и, вероятно, приведет к сканированию таблицы. Первый по-прежнему должен делать это, однако он может сузить набор результатов, используя сначала оператор LIKE (предполагая, что индекс существует в столбце someID) и, следовательно, должен выполнять меньше операций конкатенации.

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