Попытка удалить полный доступ к таблице в oracle - PullRequest
0 голосов
/ 17 января 2020

У меня есть простой запрос

select round(sum(a.wt)) as a_wt 
from db.abc a 
where a.date is null 
and a.col_no is not null 
and a.pod_cd = '367' 
and a.fant != a.rce

, и я хочу полностью удалить доступ к таблице. Есть 3 индекса, которые похожи на эти в следующей комбинации столбца

  1. col_no
  2. col_no,date,fant,pyc
  3. wagno,batno

, что можно сделать для полного доступа к таблице. enter image description here

Ответы [ 3 ]

0 голосов
/ 17 января 2020

Обычно индексы не индексируют нулевые значения, поэтому условия типа

where a.date is null 
  and a.col_no is not null 

означают просто «не использовать индекс для получения строк для этих условий»

Однако в операторе create index есть опция, позволяющая индексировать нулевые столбцы (насколько я знаю, начиная с версии 11)

create index abc_date_nulls on abc(date, 1); -- (xxx,1) is doing the trick

Таким образом, вы создадите индекс, который учитывает нулевые значения. Это может быть полезно в зависимости от селективности условия «дата равна нулю».

В противном случае или дополнительно я бы предложил проверить селективность для условия «pod_cd = 367» и построить индекс для столбца pod_cd. .

Если вы уверены, что индекс поможет, а база данных не использует его, вы можете заставить oracle использовать индекс с помощью подсказки

select /*+ index(index name) */ ... from ...

Это хорошо для Тесты или для проверки показателей воздействия могут предоставить, но, пожалуйста, будьте осторожны, используя их в производстве. Google документацию и все о недостатках для этого подхода. Никому не говорите, что я говорил вам использовать подсказки на производстве

0 голосов
/ 19 января 2020

Индексы можно использовать для проверки наличия нулей и сравнения двух столбцов друг с другом.

Настройка:

create table abc
( dt      date
, col_no  number
, pod_cd  varchar2(5)
, fant    number
, rce     number
, wt      number )
nologging;

insert /*+ append */ into abc (dt, col_no, pod_cd, fant, rce, wt)
select case mod(rownum,3) when 0 then date '2018-12-31' + mod(rownum,1000) end
     , case mod(rownum,7) when 0 then rownum end
     , case mod(rownum,2) when 1 then mod(rownum,1000) end
     , round(dbms_random.value) + 10
     , round(dbms_random.value) + 10
     , 1
from   xmltable('1 to 10000000');

create index x1 on abc (pod_cd, dt);

create index x2 on abc (fant, rce);

Проверка на нулевые значения:

select count(*) from abc a
where  a.pod_cd = '367'
and    a.dt is null;

  COUNT(*)
----------
      6667

1 row selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 2253536563

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     1 |     7 |    20   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE   |      |     1 |     7 |            |          |
|*  2 |   INDEX RANGE SCAN| X1   |  6667 | 46669 |    20   (0)| 00:00:01 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("A"."POD_CD"='367' AND "A"."DT" IS NULL)

Запрос был выполнен с использованием индекса X1, не касаясь таблицы.

Проверка на fant != rce:

select count(*)
from   abc a
where  a.fant != a.rce;

  COUNT(*)
----------
   5000666

1 row selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 29151601

------------------------------------------------------------------------------
| Id  | Operation             | Name | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |      |     1 |     6 |  6468   (1)| 00:00:01 |
|   1 |  SORT AGGREGATE       |      |     1 |     6 |            |          |
|*  2 |   INDEX FAST FULL SCAN| X2   |  5000K|    28M|  6468   (1)| 00:00:01 |
------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("A"."FANT"<>"A"."RCE")

Запрос был выполнен с использованием индекса X2, также не касаясь таблицы.

Проверка полного запроса:

create index x3 on abc(pod_cd, dt, fant, rce, col_no, wt);

select round(sum(a.wt)) as a_wt
from   abc a
where  a.dt is null
and    a.col_no is not null
and    a.pod_cd = '367'
and    a.fant != a.rce;

      A_WT
----------
       481

1 row selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 3828004431

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     1 |    16 |    28   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE   |      |     1 |    16 |            |          |
|*  2 |   INDEX RANGE SCAN| X3   |   476 |  7616 |    28   (0)| 00:00:01 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("A"."POD_CD"='367' AND "A"."DT" IS NULL)
       filter("A"."COL_NO" IS NOT NULL AND "A"."FANT"<>"A"."RCE")

Полное сканирование таблицы не всегда ужасно.

SQL> drop index x1;

Index dropped.

SQL> drop index x2;

Index dropped.

SQL> drop index x3;

Index dropped.

select round(sum(a.wt)) as a_wt 
from   abc a
where  a.dt is null 
and    a.col_no is not null 
and    a.pod_cd = '367' 
and    a.fant != a.rce;

      A_WT
----------
       481

1 row selected.

Elapsed: 00:00:00.18

Execution Plan
----------------------------------------------------------
Plan hash value: 1045519631

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |     1 |    16 |  8188   (1)| 00:00:01 |
|   1 |  SORT AGGREGATE    |      |     1 |    16 |            |          |
|*  2 |   TABLE ACCESS FULL| ABC  |   476 |  7616 |  8188   (1)| 00:00:01 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter("A"."COL_NO" IS NOT NULL AND "A"."POD_CD"='367' AND
              "A"."DT" IS NULL AND "A"."FANT"<>"A"."RCE")

Таблица AB C имеет 10 миллионов строк, и полное сканирование заняло 0,18 секунды. Это в виртуальной машине на 4-летнем ноутбуке.

0 голосов
/ 17 января 2020

Одним из вариантов будет создание Function Based Index:

create index idx_date_col_pod on ABC (nvl("date",date'1900-01-01'), nvl(col_no,0), pod_cd);

и преобразование запроса в:

select round(sum(wt)) as a_wt
  from abc
 where nvl("date",date'1900-01-01') = date'1900-01-01' -- matching means "date" column is null assuming there exists no records with this ancient date.
   and nvl(col_no,0) != 0 -- non-matching means "col_no" column is not null
   and pod_cd = 367
   and fant != rce
...