Вывод основных параметров индексов

-- blevel не должен быть больше, чем 3-4
-- clustering_factor- если он превышает 50% от числа строк таблицы, то индекс можно перестроить (а лучше перезалить таблицу с сортировкой согласно этому индексу)
-- этот % показывает поле proc_clust

SELECT owner,index_name,table_name,blevel,leaf_blocks,distinct_keys, 
       avg_data_blocks_per_key avg_data_blocks,clustering_factor cl_factor,
       num_rows,decode(num_rows,0,0,clustering_factor*100/num_rows) proc_clust,
       avg_leaf_blocks_per_key avg_leaf_blocks
 FROM dba_indexes WHERE owner ='UBC' AND blevel IS NOT null 
ORDER BY blevel desc,leaf_blocks desc 

Более точную информацию о конкретном индексе можно получить, если его проанализировать таким образом.

ANALYZE INDEX index_name VALIDATE STRUCTURE;

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

SELECT * FROM INDEX_STATS

Для того, чтобы просмотреть расширенную информацию по всем индексам, нужно создать вспомогательную таблицу

CREATE TABLE ind_stats AS SELECT * FROM sys.INDEX_STATS;

и пропустить в базе ( очень желательно в нерабочее время ) такой анонимный блок:

DECLARE
CURSOR c_ind IS
  SELECT 'analyze index '||owner||'.'||index_name||' validate structure' txt_sql
    FROM DBA_INDEXES WHERE owner IN ('UBC') -- список нужных владельцев индексов
   ORDER BY owner,index_name;
BEGIN
  DBMS_OUTPUT.PUT_LINE(SYSDATE); 
  FOR cind IN c_ind LOOP
     begin 
       toad.execute_immediate(cind.txt_sql); -- !!! убедитесь,  что это у вас есть !!!
INSERT INTO apt.ind_stats SELECT * FROM sys.INDEX_STATS;
exception WHEN others THEN -- в случае, если индекс занят, вывести сообщение DBMS_OUTPUT.PUT_LINE( cind.txt_sql);

END; END LOOP; DBMS_OUTPUT.PUT_LINE(SYSDATE); END;

Тут надо обратить внимание, что процедура execute_immediate появляется только после установки TOAD.

Для Oracle 8,9 можно воспользоваться родной аналогичной командой.

Ну и проматриваем результаты с акцентом на наиболее важные поля:

SELECT NAME, lf_rows, height, del_lf_rows, pct_used FROM apt.ind_stats
ORDER BY height DESC, lf_rows DESC

В случае, если

желательно пересоздать индекс (опять таки лучше в нерабочее время :):

ALTER INDEX your_name_index REBUILD tablespace USERS

и сделать стандартный analyze:

ANALYZE INDEX your_name_index compute statistics

Полный перечень столбцов во вьюшке

HEIGHT количество уровней индексного дерева
BLOCKS общее число блоков в индексе
NAME имя индекса 
LF_ROWS Число строк листьев (значений в индексе)
LF_BLKS Число блоков занятых листьями в B-дереве
LF_ROWS_LEN Сумма длин всех строк листьев
LF_BLK_LEN Сумма длин всех строк в ветвях В-дерева ?
BR_ROWS Число строк ветвей в B-дереве ( number of branch rows)
BR_BLKS Число блоков ветвей в B-дереве (number of branch blocks in the b-tree)
BR_ROWS_LEN Сумма длин всех блоков ветвей в B-дереве ( sum of the lengths of all the branch blocks in the b-tree )
BR_BLK_LEN Занятое пространство в блоке ветвей (useable space in a branch block)
DEL_LF_ROWS Число удаленных строк листьев в индексе
DEL_LF_ROWS_LEN Общая длина удаленных строк в индексе
DISTINCT_KEYS число уникальных значений в индексе (может включать строки, которые были удалены)
MOST_REPEATED_KEY Максимальное число повторений ключа (может включать строки, которые были удалены)
BTREE_SPACE Общая память, распределенная B-дереву
USED_SPACE Занятая память в B-дереве
PCT_USED Процент используемой памяти в B-дереве
ROWS_PER_KEY Среднее число строк на значение ключа с учетом повторений
BLKS_GETS_PER_ACCESS Ожидаемое количество согласованных чтений блоков на строку в предположении, что строка выбирается произвольно. Используется для расчета количества согласованных чтений, которые должны быть выполнены при просмотре индекса.



Запрос, показывающий индексы с размерами, большими, чем у самой таблицы.
SELECT i.TABLE_NAME,i.index_name,si.bytes size_ind, st.bytes size_tab FROM dba_indexes i,
	   (SELECT segment_name, sum(bytes) bytes 
	      FROM dba_extents WHERE owner='UBC' AND segment_type='INDEX'
	     GROUP BY segment_name) si,
	   (SELECT segment_name, sum(bytes) bytes
              FROM dba_extents WHERE owner='UBC' AND segment_type='TABLE'
             GROUP BY segment_name) st 
WHERE i.index_name=si.segment_name AND st.segment_name=i.TABLE_NAME AND st.bytes < si.bytes 

 


Индексы - кандидаты на изменение параметра PCTFREE.

Если индекс основан на столбце, который заполняется только строго по возростанию и не изменяется, например на основе последовательности, то его можно пересоздать с параметром PCTFREE=0.

Такие индексы можно поискать среди уникальных индексов на основе одного столбца :

SELECT di.index_name, di.table_name, di.pct_free 
  FROM DBA_INDEXES di, (SELECT index_name, table_name, count(*)
                          FROM DBA_IND_COLUMNS
                         GROUP BY index_name, table_name
                        HAVING count(*)=1) dc
 WHERE di.UNIQUENESS='UNIQUE' AND di.table_owner='UBC'
   AND di.index_name=dc.index_name AND di.table_name=dc.table_name
 

Изменить pct_free можно так:

ALTER INDEX name_index REBUILD tablespace USERS_S PCTFREE 0;

Этот же запрос можно использовать и для поиска сжатых уникальных индексов из одного столбца (нонсенс, но изредка бывает :) Для этого к запросу добавить

and compression='ENABLED'


Поиск индексов - кандидатов на перенос в таблспэйс для миниатюрных объектов базы данных (в моём случае до 40-64 К)


SELECT 'alter index '|| index_name||' rebuild tablespace users_ro_s STORAGE (INITIAL 4K);',
       table_name, distinct_keys, num_rows, bytes/1024
  FROM USER_INDEXES i, dba_segments s
 WHERE i.tablespace_name<>'USERS_RO_S' AND blevel<2 AND num_rows<300
   and segment_name=index_name


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

 


Индексы с малой избирательной способностью:


SELECT index_name, distinct_keys, num_rows, 
       to_char(decode(num_rows,0,1,num_rows)/decode(distinct_keys,0,1,distinct_keys),'999G999D00') rows_on_keys
  FROM user_indexes
 WHERE uniqueness<>'UNIQUE' and decode(num_rows,0,1,num_rows)/decode(distinct_keys,0,1,distinct_keys)>2
 ORDER BY decode(num_rows,0,1,num_rows)/decode(distinct_keys,0,1,distinct_keys)   desc

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

Эти индексы, если они всё же нужны, также являются кандидатами на сжатие


 

 

Хостинг от uCoz