Системна інформація в індексах, Інші СУБД, Бази даних, статті

Ця стаття присвячена обговоренню структури записів в індексах (пам’ятаєте, я збирався частину випусків присвячувати індексам ;). За мотивами відповіді Тома Кайта на питання, задане 14 червня 2003.

Системна інформація в індексах


Том,

Після аналізу індексу (analyze … validate) Я поділив LF_ROWS_LEN на LF_ROWS і виявив значення на 12 байтів більше, ніж довжина ключа. Я очікував збільшення тільки на 6 байтів – розмір rowid, А звідки взялися інші 6 байтів? Може, я неправильно вважаю?

SQL> analyze index IDX_TBLACCOUNT validate structure;
Index analyzed
SQL> select * from index_stats;
HEIGHT 3
BLOCKS 18056
NAME IDX_TBLACCOUNT
PARTITION_NAME
LF_ROWS 5796880
LF_BLKS 16868
LF_ROWS_LEN 75359440
LF_BLK_LEN 7996
BR_ROWS 16867
BR_BLKS 57
BR_ROWS_LEN 237396
BR_BLK_LEN 8028
DEL_LF_ROWS 7655
DEL_LF_ROWS_LEN 99515
DISTINCT_KEYS 20
MOST_REPEATED_KEY 4228703
BTREE_SPACE 135334124
USED_SPACE 75596836
PCT_USED 56
ROWS_PER_KEY 289844
BLKS_GETS_PER_ACCESS 144925.5
PRE_ROWS 0
PRE_ROWS_LEN 0

LF_ROWS_LEN/LF_ROWS = 75359440/5796880 = 13


Довжина стовпця – 1 байт (varchar2(1)).

SQL> select * from user_ind_columns where index_name = “IDX_TBLACCOUNT”;
INDEX_NAME IDX_TBLACCOUNT
TABLE_NAME TBLACCOUNT
COLUMN_NAME AC_STATUS
COLUMN_POSITION 1
COLUMN_LENGTH 1
DESCEND ASC
SQL> select * from user_tab_columns where table_name=”TBLACCOUNT” and column_name=”AC_STATUS”;
TABLE_NAME TBLACCOUNT
COLUMN_NAME AC_STATUS
DATA_TYPE VARCHAR2
DATA_TYPE_MOD
DATA_TYPE_OWNER
DATA_LENGTH 1
DATA_PRECISION
DATA_SCALE
NULLABLE Y
COLUMN_ID 67
DEFAULT_LENGTH
DATA_DEFAULT
NUM_DISTINCT 17
LOW_VALUE 30
HIGH_VALUE 74
DENSITY 0.05882352
NUM_NULLS 0
NUM_BUCKETS 1
LAST_ANALYZED 6/14/2003
SAMPLE_SIZE 235526
CHARACTER_SET_NAME CHAR_CS
CHAR_COL_DECL_LENGTH 1
GLOBAL_STATS NO
USER_STATS NO
AVG_COL_LEN 1

Аналізую інший індекс, по тій же таблиці, і знову отримую 12 додаткових байтів:

SQL> analyze index idx_tblaccount_stssch validate structure;
Index analyzed
SQL> select * from index_stats;
HEIGHT 3
BLOCKS 18845
NAME IDX_TBLACCOUNT_STSSCH
PARTITION_NAME
LF_ROWS 5794493
LF_BLKS 17096
LF_ROWS_LEN 121620457
LF_BLK_LEN 7996
BR_ROWS 17095
BR_BLKS 53
BR_ROWS_LEN 390029
BR_BLK_LEN 8028
DEL_LF_ROWS 5268
DEL_LF_ROWS_LEN 110621
DISTINCT_KEYS 22291
MOST_REPEATED_KEY 553444
BTREE_SPACE 137125100
USED_SPACE 122010486
PCT_USED 89
ROWS_PER_KEY 259.94764703
BLKS_GETS_PER_ACCESS 133.473823516217
PRE_ROWS 0
PRE_ROWS_LEN 0

LF_ROWS_LEN / LF_ROWS = 121620457/5794493 = 20.99 (у нас 12880 рядків зі значеннями NULL у першому стовпчику)


Отримуємо знову DATE (7 байтів) + роздільник? – Прокоментуйте, будь ласка, (1 байт) + varchar2(1) (1 байт) = 9 байтів.


12 байтів використано системою для своїх цілей.

SQL> select * from user_tab_columns where table_name=”TBLACCOUNT” and column_name=”AC_SCHEDULETIME”;
TABLE_NAME TBLACCOUNT
COLUMN_NAME AC_SCHEDULETIME
DATA_TYPE DATE
DATA_TYPE_MOD
DATA_TYPE_OWNER
DATA_LENGTH 7
DATA_PRECISION
DATA_SCALE
NULLABLE Y
COLUMN_ID 72
DEFAULT_LENGTH
DATA_DEFAULT
NUM_DISTINCT 4941
LOW_VALUE 78640714110101
HIGH_VALUE C7C70C1F0E0201
DENSITY 0.00020238
NUM_NULLS 12880
NUM_BUCKETS 1
LAST_ANALYZED 6/14/2003
SAMPLE_SIZE 235526
CHARACTER_SET_NAME
CHAR_COL_DECL_LENGTH
GLOBAL_STATS NO
USER_STATS NO
AVG_COL_LEN 7

Відповідь Тома Кайта


Системою використовується 4/5 байтів.


Стовпець типу varchar2 має початковий байт довжини, так що varchar2(1) займає, мінімум, 2 байта. Треба також врахувати індикатор null-значення. Значення rowid теж зберігається як “рядок” (з початковими байтами довжини).


Отже, для ключа типу varchar2(1) маємо:
1 байт “довжини”, 1 байт “даних”, 1 байт “довжини rowid”, 6 байтів даних rowid = 9 байтів.


При тестуванні я отримую 12 байтів на рядок у версії 9203 для ОС RedHat Linux на платформі Intel. Це дуже легко визначити:

ops$tkyte@ORA920> create table t ( x varchar2(20) );
Table created.
ops$tkyte@ORA920> create index t_idx on t(x);
Index created.
ops$tkyte@ORA920> begin
2 for i in 1 .. 20
3 loop
4 execute immediate “truncate table t”;
5
6 insert into t
7 select rpad(chr(rownum),i,chr(rownum))
8 from all_objects
9 where rownum <= 255;
10
11 execute immediate “analyze index t_idx validate structure”;
12 for x in ( select lf_rows_len, lf_rows, lf_rows_len/lf_rows bytes_per_entry
13 from index_stats )
14 loop
15 dbms_output.put_line
16 ( “Width = ” // i // ” lf_rows_len = ” // x.lf_rows_len //
17 ” bytes/entry = ” // x.bytes_per_entry );
18 end loop;
19 end loop;
20 end;
21 /
Width = 1 lf_rows_len = 3315 bytes/entry = 13
Width = 2 lf_rows_len = 3570 bytes/entry = 14
Width = 3 lf_rows_len = 3825 bytes/entry = 15
Width = 4 lf_rows_len = 4080 bytes/entry = 16
Width = 5 lf_rows_len = 4335 bytes/entry = 17
Width = 6 lf_rows_len = 4590 bytes/entry = 18
Width = 7 lf_rows_len = 4845 bytes/entry = 19
Width = 8 lf_rows_len = 5100 bytes/entry = 20
Width = 9 lf_rows_len = 5355 bytes/entry = 21
Width = 10 lf_rows_len = 5610 bytes/entry = 22
Width = 11 lf_rows_len = 5865 bytes/entry = 23
Width = 12 lf_rows_len = 6120 bytes/entry = 24
Width = 13 lf_rows_len = 6375 bytes/entry = 25
Width = 14 lf_rows_len = 6630 bytes/entry = 26
Width = 15 lf_rows_len = 6885 bytes/entry = 27
Width = 16 lf_rows_len = 7140 bytes/entry = 28
Width = 17 lf_rows_len = 7395 bytes/entry = 29
Width = 18 lf_rows_len = 7650 bytes/entry = 30
Width = 19 lf_rows_len = 7905 bytes/entry = 31
Width = 20 lf_rows_len = 8160 bytes/entry = 32
PL/SQL procedure successfully completed.

Отже, при довжині 20 ми маємо:

 довжина 1 + дані 20 + довжина 1 + дані 6

32-28 = 4

У кожному рядку – на 4 байта “більше”, а якщо додати ще один великий стовпець:

ops$tkyte@ORA920> drop table t;
Table dropped.
ops$tkyte@ORA920> create table t ( x varchar2(20), y char(100) default “x” );
Table created.
ops$tkyte@ORA920> create index t_idx on t(x,y);
Index created.
ops$tkyte@ORA920> begin
2 for i in 1 .. 20
3 loop
4 execute immediate “truncate table t”;
5
6 insert into t (x)
7 select rpad(chr(rownum),i,chr(rownum))
8 from all_objects
9 where rownum <= 255;
10
11 execute immediate “analyze index t_idx validate structure”;
12 for x in ( select lf_rows_len, lf_rows, lf_rows_len/lf_rows bytes_per_entry
13 from index_stats )
14 loop
15 dbms_output.put_line
16 ( “Width = ” // i // ” lf_rows_len = ” // x.lf_rows_len //
17 ” bytes/entry = ” // x.bytes_per_entry );
18 end loop;
19 end loop;
20 end;
21 /
Width = 1 lf_rows_len = 29070 bytes/entry = 114
Width = 2 lf_rows_len = 29325 bytes/entry = 115
Width = 3 lf_rows_len = 29580 bytes/entry = 116
Width = 4 lf_rows_len = 29835 bytes/entry = 117
Width = 5 lf_rows_len = 30090 bytes/entry = 118
Width = 6 lf_rows_len = 30345 bytes/entry = 119
Width = 7 lf_rows_len = 30600 bytes/entry = 120
Width = 8 lf_rows_len = 30855 bytes/entry = 121
Width = 9 lf_rows_len = 31110 bytes/entry = 122
Width = 10 lf_rows_len = 31365 bytes/entry = 123
Width = 11 lf_rows_len = 31620 bytes/entry = 124
Width = 12 lf_rows_len = 31875 bytes/entry = 125
Width = 13 lf_rows_len = 32130 bytes/entry = 126
Width = 14 lf_rows_len = 32385 bytes/entry = 127
Width = 15 lf_rows_len = 32640 bytes/entry = 128
Width = 16 lf_rows_len = 32895 bytes/entry = 129
Width = 17 lf_rows_len = 33150 bytes/entry = 130
Width = 18 lf_rows_len = 33405 bytes/entry = 131
Width = 19 lf_rows_len = 33660 bytes/entry = 132
Width = 20 lf_rows_len = 33915 bytes/entry = 133
PL/SQL procedure successfully completed.

Можна очікувати:

 довжина 1 дані 20 довжина 1 (так, CHAR – Всього лише VARCHAR2, Доповнений пробілами – довжина теж зберігається) дані 100 довжина 1 дані 6
— 133 – 129 = 4 додаткових байта

Коментар читача від 15 червня 2003


Цікаво, навіщо для значення rowid довжина, – що, ідентифікатори рядків можуть бути змінної довжини? І звідки беруться ці 4 байта? Навіщо вони потрібні?


Відповідь Тома Кайта


Вони просто “є” (тобто, потрібні)


Коментар читача від 18 червня 2003


Ось дамп блоку:

row#0[536] flag: —–, lock: 0
col 0; len 20; (20): 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
col 1; len 6; (6): 02 40 03 8d 00 00
row#1[566] flag: —–, lock: 0
col 0; len 20; (20): 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
col 1; len 6; (6): 02 40 03 8d 00 01
row#2[596] flag: —–, lock: 0
col 0; len 20; (20): 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03
col 1; len 6; (6): 02 40 03 8d 00 02
row#3[626] flag: —–, lock: 0
col 0; len 20; (20): 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04
col 1; len 6; (6): 02 40 03 8d 00 03

Судячи з нього, кожен рядок займає 30 байтів: рядки починаються зі зсувів 536, 566, 596, 626… Не міг би ти пояснити, звідки взялися 2 байта в твоїх результати?


Відповідь Тома Кайта


Я не займаюся інтерпретацією результатів дампів. Ви вивчаєте “звіт” про блок, а не сам блок. Див поля flags, row#, І т.д. Вважайте, що це “дані, які необхідні серверу для управління даними користувача”


Все просто – скільки треба, стільки система і використовує.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*