powered by simpleCommunicator - 2.0.53     © 2025 Programmizd 02
Форумы / Oracle [игнор отключен] [закрыт для гостей] / index range vs index skip scan
11 сообщений из 11, страница 1 из 1
index range vs index skip scan
    #39870474
mlc
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Всем привет.

Есть неуникальный индекс по двум полям.
dbms_metadata.get_ddl
Код: plsql
1.
2.
3.
4.
5.
6.
CREATE INDEX "SYSMD"."IDX_OPRCRE" ON "SYSMD"."OPR_CRE" ("DDATE", "BR") 
  PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS COMPRESS 2 
  STORAGE(INITIAL 1048576 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
  BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
  TABLESPACE "TBS_SYS"


Ожидается, что при его использовании в плане будет range scan, однако, каким-то чудом туда влезает skip scan, так еще и кардинальность считает неверно - конечная выборка тысяч 300. Статистика актуальная.
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
explain plan for 
    SELECT oc.ddate
     FROM sysmd.opr_cre oc
    WHERE oc.br = 1
      AND oc.ddate >= date'2019-09-01'
      AND oc.ndn IS NULL
/

Plan hash value: 361932983
 
---------------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name              | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |                   |  4236K|    52M| 53800   (1)| 00:00:03 |
|*  1 |  TABLE ACCESS BY INDEX ROWID BATCHED| OPR_CRE           |  4236K|    52M| 53800   (1)| 00:00:03 |
|*  2 |   INDEX SKIP SCAN                   | IDX_OPRCRE        |  4236K|       |  9184   (1)| 00:00:01 |
---------------------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   1 - filter("DOC"."NDN" IS NULL)
   2 - access("DOC"."DDATE">=TO_DATE(' 2019-09-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND 
              "DOC"."BR"=1)
       filter("DOC"."BR"=1)


1. Вопрос собственно, почему оптиизатор выбрал SS и где-нужно подкрутить, чтобы был RS?
2. Дублирование access предиката фильтром filter("DOC"."BR"=1) не делает двойную работу? Я имею ввиду после выбора по индексу не перефильтровывается ли еще раз filter("DOC"."BR"=1) ?
...
Рейтинг: 0 / 0
index range vs index skip scan
    #39870492
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
mlc,

покажите статистику используя этот скрипт: https://github.com/xtender/xt_scripts/blob/master/stats/tab.sql

Без дополнительной информации в голову приходит только вариант, что в статистике Low_value столбца DDATE больше чем 2019-09-01 и параметр optimizer_index_cost_adj занижен
...
Рейтинг: 0 / 0
index range vs index skip scan
    #39870496
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
mlc,

ну и в целом, с такими вопросами надо сначала смотреть в 10053
...
Рейтинг: 0 / 0
index range vs index skip scan
    #39870517
mlc
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
xtender,

optimizer_index_cost_adj дефолтный.
Код: plsql
1.
2.
3.
4.
5.
6.
show parameter optimizer_index_cost_adj
/

NAME                     TYPE    VALUE 
------------------------ ------- ----- 
optimizer_index_cost_adj integer 100   


Статистику сейчас соберу.
...
Рейтинг: 0 / 0
index range vs index skip scan
    #39870534
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
mlc,

10053 сразу покажи
...
Рейтинг: 0 / 0
index range vs index skip scan
    #39870558
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
xtenderв статистике Low_value столбца DDATE больше чем 2019-09-01
Я скорее предположил бы обратное - в табличку вставили пару записей за будущий год :)
Еще бывают развлечения с интервальным секционированием, но тут вроде не оно.
...
Рейтинг: 0 / 0
index range vs index skip scan
    #39870593
Фотография -2-
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Skip scan выгоден, если мизерное количество уникальных значений ddate и количество br=1 тоже незначительное.
...
Рейтинг: 0 / 0
index range vs index skip scan
    #39870602
mlc
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
xtender,

table stat
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
col owner           for a15
col table_name      for a30
col partition_name  for a20
col index_name      for a30
col st_lock         for a7
col #               for 999
col cols            for a150
select
    t.owner
   ,t.table_name
   ,t.PARTITION_NAME
   ,t.PARTITION_POSITION as "#"
   ,t.stattype_locked as st_lock
   ,t.stale_stats
   ,t.global_stats
   ,t.user_stats
   ,t.NUM_ROWS
   ,t.BLOCKS
   ,t.EMPTY_BLOCKS
   ,t.AVG_ROW_LEN
   ,t.AVG_SPACE
   ,t.LAST_ANALYZED 
from dba_tab_statistics t 
where  
      t.owner      ='SYSMD'
  and t.table_name = 'OPR_CRE'
/


Код: plsql
1.
2.
3.
4.
5.
OWNER           TABLE_NAME                     PARTITION_NAME          # ST_LOCK STA GLO USE   NUM_ROWS     BLOCKS EMPTY_BLOCKS AVG_ROW_LEN  AVG_SPACE LAST_ANALYZED      
--------------- ------------------------------ -------------------- ---- ------- --- --- --- ---------- ---------- ------------ ----------- ---------- -------------------
SYSMD           OPR_CRE                                                          NO  YES NO  1692400315   13001496            0          49          0 01.10.2019 15:39:19

Elapsed: 00:00:00.100


index stat
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
select 
    ix.owner
   ,ix.index_name
   ,ix.num_rows
   ,ix.distinct_keys
   ,ix.blevel
   ,ix.leaf_blocks
   ,ix.clustering_factor as cl_factor
   ,ix.last_analyzed
   ,ix.global_stats
   ,ix.user_stats
   ,(select ltrim(max(sys_connect_by_path(ic.column_name,',')),',')
     from dba_ind_columns ic 
     start with ic.INDEX_OWNER=ix.owner
            and ic.INDEX_NAME = ix.index_name
            and ic.COLUMN_POSITION=1
     connect by ic.INDEX_OWNER=ix.owner
            and ic.INDEX_NAME = ix.index_name
            and ic.COLUMN_POSITION= prior ic.COLUMN_POSITION+1
     ) cols
from dba_indexes ix 
where 
      ix.table_owner = 'SYSMD'
  and ix.table_name  = 'OPR_CRE'
/


Код: plsql
1.
2.
3.
4.
5.
OWNER           INDEX_NAME                       NUM_ROWS DISTINCT_KEYS     BLEVEL LEAF_BLOCKS  CL_FACTOR LAST_ANALYZED       GLO USE COLS
--------------- ------------------------------ ---------- ------------- ---------- ----------- ---------- ------------------- --- --- ---------------------
SYSMD           OPR_CRE                        1687796175          5158          3     4290310   17805710 01.10.2019 15:51:40 YES NO  DDATE,BR

Elapsed: 00:00:00.355


columns stat
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
declare
   
   l_column_name    constant number := 30;
   l_num_distinct   constant number := 12;
   l_low_value      constant number := 30;
   l_high_value     constant number := 30;
   --l_density        constant number := 10;
   l_num_nulls      constant number := 10;
   l_num_buckets    constant number := 10;
   l_last_analyzed  constant number := 20;
   l_sample_size    constant number := 11;
   l_global_stats   constant number := 5 ;
   l_user_stats     constant number := 5 ;
   l_avg_col_len    constant number := 5 ;
   l_histogram      constant number := 20;
   
   full_len         constant number := 25
                                       + l_column_name + l_num_distinct + l_low_value + l_high_value 
                                       -- + l_density
                                       + l_num_nulls + l_num_buckets + l_last_analyzed + l_sample_size 
                                       + l_global_stats + l_user_stats + l_avg_col_len + l_histogram
                                       ;
   function raw_to_num(i_raw raw)
   return varchar2
   as
      m_n number;
   begin
      dbms_stats.convert_raw_value(i_raw,m_n);
      return m_n;
   exception when others then return 'ERROR:'||sqlerrm;
   end;
     
   function raw_to_date(i_raw raw)
   return date
   as
      m_n date;
   begin
      dbms_stats.convert_raw_value(i_raw,m_n);
      return m_n;
   end;
     
   function raw_to_varchar2(i_raw raw)
   return varchar2
   as
      m_n varchar2(4000);
   begin
      dbms_stats.convert_raw_value(i_raw,m_n);
      return m_n;
   end;
   
   function val_to_output(p_datatype varchar2,p_value raw) 
   return varchar2
   is
     res varchar2(4000);
   begin
      res := case 
           when p_datatype in ('CHAR','VARCHAR2')                       then raw_to_varchar2(p_value)
           when p_datatype = 'DATE' or p_datatype like 'TIMESTAMP%'     then to_char(raw_to_date(p_value),'yyyy-mm-dd hh24:mi:ss')
           when p_datatype = 'NUMBER'                                   then raw_to_num(p_value)
           when p_datatype = 'FLOAT'                                    then raw_to_num(p_value)
           else 'tp='||p_datatype
        end;
      return nvl(res,'NULL');
   end;

   function xrpad(str1 in varchar2,len int,pad varchar2)
   return varchar2
   is
      str2 varchar2(32676):=nvl(replace(str1,chr(10),' '),' ');
   begin
      --str2:=regexp_replace(str2,'[[:cntrl:]]','~');
      if regexp_like(str2,'[[:cntrl:]]') then 
         select 'DUMP:'||dump(str2,17) into str2 from dual;
      end if;
      return rpad(str2,len,pad);
   end;
begin
   dbms_output.put_line( rpad('-',full_len,'-'));
   dbms_output.put_line( '| '
      ||rpad('column_name'                                 ,l_column_name   ,' ') ||'| '
      ||rpad('num_distinct'                                ,l_num_distinct  ,' ') ||'| '
      ||rpad('low_value'                                   ,l_low_value     ,' ') ||'| '
      ||rpad('high_value'                                  ,l_high_value    ,' ') ||'| '
      --||rpad('density'                                     ,l_density       ,' ') ||'| '
      ||rpad('num_nulls'                                   ,l_num_nulls     ,' ') ||'| '
      ||rpad('num_buckets'                                 ,l_num_buckets   ,' ') ||'| '
      ||rpad('last_analyzed'                               ,l_last_analyzed ,' ') ||'| '
      ||rpad('sample_size'                                 ,l_sample_size   ,' ') ||'| '
      ||rpad('global_stats'                                ,l_global_stats  ,' ') ||'| '
      ||rpad('user_stats'                                  ,l_user_stats    ,' ') ||'| '
      ||rpad('avg_col_len'                                 ,l_avg_col_len   ,' ') ||'| '
      ||rpad('histogram'                                   ,l_histogram     ,' ') ||'| '
      );
   dbms_output.put_line( rpad('-',full_len,'-'));
   
   for r in (
         select 
             tc.column_name
            ,cs.num_distinct
            ,tc.DATA_TYPE
            ,cs.low_value
            ,cs.high_value
            ,cs.density
            ,cs.num_nulls
            ,cs.num_buckets
            ,cs.last_analyzed
            ,cs.sample_size
            ,cs.global_stats
            ,cs.user_stats
            ,cs.avg_col_len
            ,cs.HISTOGRAM
         from dba_tab_col_statistics cs 
             ,dba_tab_columns tc
         where 
                tc.owner       = 'SYSMD'
            and tc.table_name  = 'OPR_CRE'
            and tc.OWNER       = cs.owner(+)
            and tc.TABLE_NAME  = cs.table_name(+)
            and tc.COLUMN_NAME = cs.column_name(+)
         order by tc.COLUMN_ID
   )
   loop
      dbms_output.put_line( '| '
         ||xrpad(r.column_name                                 ,l_column_name   ,' ') ||'| '
         ||xrpad(r.num_distinct                                ,l_num_distinct  ,' ') ||'| '
         ||xrpad(val_to_output(r.data_type,r.low_value)        ,l_low_value     ,' ') ||'| '
         ||xrpad(val_to_output(r.data_type,r.high_value)       ,l_high_value    ,' ') ||'| '
         --||xrpad(r.density                                     ,l_density       ,' ') ||'| '
         ||xrpad(r.num_nulls                                   ,l_num_nulls     ,' ') ||'| '
         ||xrpad(r.num_buckets                                 ,l_num_buckets   ,' ') ||'| '
         ||xrpad(to_char(r.last_analyzed,'yyyy-mm-dd hh24:mi') ,l_last_analyzed ,' ') ||'| '
         ||xrpad(r.sample_size                                 ,l_sample_size   ,' ') ||'| '
         ||xrpad(r.global_stats                                ,l_global_stats  ,' ') ||'| '
         ||xrpad(r.user_stats                                  ,l_user_stats    ,' ') ||'| '
         ||xrpad(r.avg_col_len                                 ,l_avg_col_len   ,' ') ||'| '
         ||xrpad(r.histogram                                   ,l_histogram     ,' ') ||'| '
         );
    end loop;
   dbms_output.put_line( rpad('-',full_len,'-'));
end;
/


Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| column_name                   | num_distinct| low_value                     | high_value                    | num_nulls | num_bucket| last_analyzed       | sample_size| globa| user_| avg_c| histogram           | 
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| BR                            | 2           | 1                             | 2                             | 0         | 2         | 2019-10-01 15:39    | 338480063  | YES  | NO   | 3    | FREQUENCY           | 
| DDATE                         | 3761        | 2008-11-20 00:00:00           | 2019-09-11 00:00:00           | 0         | 1         | 2019-10-01 15:39    | 338480063  | YES  | NO   | 8    | NONE                | 
| TYP                           | 8           | 0                             | 11                            | 0         | 8         | 2019-10-01 15:39    | 338480063  | YES  | NO   | 3    | FREQUENCY           | 
| STAT                          | 15557       | 1                             | 601730427                     | 0         | 254       | 2019-10-01 15:39    | 338480063  | YES  | NO   | 5    | HEIGHT BALANCED     | 
| NDN                           | 50925       | 54                            | 1735118583                    | 1692349295| 1         | 2019-10-01 15:39    | 10204      | YES  | NO   | 2    | NONE                | 
| BLK                           | 28070       | 182933                        | 1733718487                    | 1692372245| 254       | 2019-10-01 15:39    | 5614       | YES  | NO   | 2    | HEIGHT BALANCED     | 
| VALUE                         | 1           | 0                             | 0                             | 0         | 1         | 2019-10-01 15:39    | 338480063  | YES  | NO   | 2    | NONE                | 
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


PL/SQL procedure successfully completed.

Elapsed: 00:00:01.696


Сейчас трассу сделаю.
...
Рейтинг: 0 / 0
index range vs index skip scan
    #39870606
mlc
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
-2-,

По сути сейчас приближено к тому, что вы описали. Только при SS кардинальность улетает в космос и остальная часть запроса из-за этого куска также неверно считается.
...
Рейтинг: 0 / 0
index range vs index skip scan
    #39870635
mlc
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mlc,

Кстати, посмотрел результаты выборки, оказывается, что конечная выборка вовсе 13 строк.
...
Рейтинг: 0 / 0
index range vs index skip scan
    #39870639
Фотография -2-
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mlcкардинальность улетает в космосУ ddate нет гистограммы. Это не позволяет оптимизатору оценить процент отбираемых строк.
...
Рейтинг: 0 / 0
11 сообщений из 11, страница 1 из 1
Форумы / Oracle [игнор отключен] [закрыт для гостей] / index range vs index skip scan
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]