Отображать даты в плане объяснения как литералы - PullRequest
0 голосов
/ 08 ноября 2018
SELECT DISTINCT i.name, i.daily_cost
FROM edu_event.items i
WHERE i.purchase_date BETWEEN DATE'2015-01-01' AND DATE'2015-12-31';

Для этого запроса выбран следующий план выполнения:

----------------------------------------------------------------------------
| Id  | Operation          | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |       |  5750 |   213K|   206   (1)| 00:00:01 |
|   1 |  HASH UNIQUE       |       |  5750 |   213K|   206   (1)| 00:00:01 |
|*  2 |   TABLE ACCESS FULL| ITEMS |  5750 |   213K|   205   (1)| 00:00:01 |
----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter("I"."PURCHASE_DATE">=TO_DATE('2015-01-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND "I"."PURCHASE_DATE"<=TO_DATE('2015-12-31 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))

Как видите, исходные литералы даты заменены функциями to_date. Можно ли это как-то отключить? Этот формат больше, но он не дает больше информации, поэтому он мне не нужен. Может ли разработчик SQL преобразовать его обратно программным путем?

Ответы [ 2 ]

0 голосов
/ 08 ноября 2018

Как отмечалось в другом ответе, именно так Oracle переписывает литерал DATE.

Например, при определении многораздельной таблицы с использованием литералов DATE, как показано ниже.

create table TEST 
(id NUMBER,
 PART_DATE DATE
)
PARTITION BY RANGE (PART_DATE)
INTERVAL(NUMTOYMINTERVAL(1, 'MONTH'))
( 
   PARTITION p1 VALUES LESS THAN (DATE'2018-08-01'), 
   PARTITION p2 VALUES LESS THAN (DATE'2018-09-01'),
   PARTITION p3 VALUES LESS THAN (DATE'2018-10-01')
);

... вы видите HIGH_VALUES разделов как вызовы функций to_date:

TO_DATE(' 2018-08-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
TO_DATE(' 2018-09-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
TO_DATE(' 2018-10-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')

Что важно - Oracle понимает value даты .

Например, этот запрос ...

select * from TEST where PART_DATE = DATE'2018-09-15';

... производит следующий план выполнения

-----------------------------------------------------------------------------------------------
| Id  | Operation              | Name | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
-----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |      |     1 |    22 |     2   (0)| 00:00:01 |       |       |
|   1 |  PARTITION RANGE SINGLE|      |     1 |    22 |     2   (0)| 00:00:01 |     3 |     3 |
|*  2 |   TABLE ACCESS FULL    | TEST |     1 |    22 |     2   (0)| 00:00:01 |     3 |     3 |
-----------------------------------------------------------------------------------------------

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

   2 - filter("PART_DATE"=TO_DATE(' 2018-09-15 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))

Обратите внимание, что предикат FILTER использует вызов функции to_date, , но Pstart и Pstop указывают на один раздел (# 3)

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

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

Напротив, при доступе к приведенной выше таблице с предикатом PART_DATE = SYSDATE вы получаете план выполнения, указывающий на KEY раздел.

 |*  2 |   TABLE ACCESS FULL    | TEST |     1 |    22 |     2   (0)| 00:00:01 |   KEY |   KEY |

Это означает, что Oracle знает, что получит доступ только к одному разделу, но не знает, какой именно.

0 голосов
/ 08 ноября 2018

Это то, что Oracle делает за кулисами, а не специальное представление SQL Developer. Формат не может быть изменен:

SQL> explain plan for
  2  with rec (d) as (select sysdate from dual)
  3  select *
  4    from rec
  5   where d > date '2018-01-01';

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 4034615273

-----------------------------------------------------------------
| Id  | Operation        | Name | Rows  | Cost (%CPU)| Time     |
-----------------------------------------------------------------
|   0 | SELECT STATEMENT |      |     1 |     2   (0)| 00:00:01 |
|*  1 |  FILTER          |      |       |            |          |
|   2 |   FAST DUAL      |      |     1 |     2   (0)| 00:00:01 |
-----------------------------------------------------------------

Predicate Information (identified by operation id):

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

   1 - filter(SYSDATE@!>TO_DATE(' 2018-01-01 00:00:00', 'syyyy-mm-dd
              hh24:mi:ss'))

15 rows selected.

Вы можете удалить предикатную информацию, используя формат параметр DBMS_XPLAN.DISPLAY () , но не изменять его внешний вид

SQL> select * from table(dbms_xplan.display(null, null, '-PREDICATE'));

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 4034615273

-----------------------------------------------------------------
| Id  | Operation        | Name | Rows  | Cost (%CPU)| Time     |
-----------------------------------------------------------------
|   0 | SELECT STATEMENT |      |     1 |     2   (0)| 00:00:01 |
|   1 |  FILTER          |      |       |            |          |
|   2 |   FAST DUAL      |      |     1 |     2   (0)| 00:00:01 |
-----------------------------------------------------------------

9 rows selected.
...