-- Anlage der Testtabelle
create table bi_test4
as
select rownum rn
, mod(rownum, 2) col1
, mod(rownum, 100) col2
, mod(rownum, 100000) col3
, lpad('*', 100, '*') col4
from dual
connect by level <= 1000000;
-- Anlage von Statistiken
exec DBMS_STATS.GATHER_TABLE_STATS(user, 'bi_test4', cascade => true, estimate_percent => 100)
Die Größenangaben nehme ich üblicherweise aus USER_SEGMENTS. Laut Dokumentation bedeutet die Block-Angabe "Size, in Oracle blocks, of the segment":
select BYTES , BLOCKS , EXTENTS from user_segments where segment_name = 'BI_TEST4' BYTES BLOCKS EXTENTS ---------- ---------- ---------- 142606336 8704 87
Wenn ich mir aber die Angaben aus USER_TABLES ansehe, finde ich diese 8704 Blocks nicht wieder:
select NUM_ROWS , BLOCKS , EMPTY_BLOCKS , AVG_SPACE , CHAIN_CNT , AVG_ROW_LEN from user_tables where table_name = 'BI_TEST4'; NUM_ROWS BLOCKS EMPTY_BLOCKS AVG_SPACE CHAIN_CNT AVG_ROW_LEN -------- ---------- ------------ ---------- ---------- ----------- 1000000 8413 0 0 0 116
Laut Doku sind die BLOCKS hier die "Number of used data blocks in the table". Zu den EMPTY_BLOCKS heisst es: "Number of empty (never used) data blocks in the table. This column is populated only if you collect statistics on the table using the
ANALYZE statement." Na gut, dann fragen wir eben ANALYZE, obwohl ich davon eigentlich komplett abgekommen war, da ANALYZE bei der Statistikerhebung nicht mehr das Mittel der Wahl ist. Aber auch dazu sagt die Dokumentation etwas:Oracle recommends using the more versatileANALYZE liefert im gegebenen Fall Folgendes (und benötigt dazu mehr Zeit als DBMS_STATS.GATHER_TABLE_STATS):DBMS_STATSpackage for gathering optimizer statistics, but you must use theANALYZEstatement to collect statistics unrelated to the optimizer, such as empty blocks, average space, and so forth.
select NUM_ROWS , BLOCKS , EMPTY_BLOCKS , AVG_SPACE , CHAIN_CNT , AVG_ROW_LEN from user_tables where table_name = 'BI_TEST4'; NUM_ROWS BLOCKS EMPTY_BLOCKS AVG_SPACE CHAIN_CNT AVG_ROW_LEN -------- ---------- ------------ ---------- ---------- ----------- 1000000 8413 291 1662 0 119
In der Summe komme ich damit wieder auf einen bekannten Wert: 8413 + 291 = 8704. Also sind die Blocks aus USER_TABLES diejenigen unterhalb der HighWaterMark? Klingt plausibel. Aber es gibt noch eine Meinung zum Thema, nämlich die des DBMS_SPACE-Packages, das Tom Kyte in seiner show_space-Procedure verwendet:
SQL> exec show_space('BI_TEST4')
Unformatted Blocks ..................... 0
FS1 Blocks (0-25) ..................... 0
FS2 Blocks (25-50) ..................... 0
FS3 Blocks (50-75) ..................... 0
FS4 Blocks (75-100)..................... 0
Full Blocks ..................... 8,326
Total Blocks............................ 8,704
Total Bytes............................. 142,606,336
Total MBytes............................ 136
Unused Blocks........................... 291
Unused Bytes............................ 4,767,744
Last Used Ext FileId.................... 4
Last Used Ext BlockId................... 218,368
Last Used Block......................... 221
Die 8704 werden dadurch ein weiteres Mal bestätigt, so dass ich davon ausgehe, dass es sich dabei um die tatsächliche Gesamtzahl der Blocks handelt. Ebenfalls bestätigt werden die Blocks oberhalb der HWM: ANALYZE und show_space kommen beide auf 291. Was ich aber noch nicht verstehe, ist die Zählung der gefüllten Blocks in show_space. Da würde ich annehmen, dass die Summe aus Unformatted Blocks + FS1 Blocks + ... + FS4 Blocks + Full Blocks wieder die 8413 aus USER_TABLES wäre - aber hier sind es 8326. Es fehlen also 87 Blocks. Mal sehen, ob ich die noch irgendwo finde...
Nachtrag: bei genauerer Durchsicht des bereits verlinkten AskTom-Threads findet sich ein Hinweis auf die Differenz - anscheind ergeben sich Abweichungen durch direct path Operationen. Deshalb ein weiterer Test:
create table bi_test5
as
select *
from bi_test4
where 1 = 0;
-- INSERT ohne APPEND-Hint statt CTAS, um direct path zu vermeiden
insert into bi_test5
select *
from bi_test4;
exec DBMS_STATS.GATHER_TABLE_STATS(user, 'bi_test5', estimate_percent => 100)
analyze table BI_TEST5 compute statistics;
select NUM_ROWS
, BLOCKS
, EMPTY_BLOCKS
, AVG_SPACE
, CHAIN_CNT
, AVG_ROW_LEN
from user_tables
where table_name = 'BI_TEST5';
NUM_ROWS BLOCKS EMPTY_BLOCKS AVG_SPACE CHAIN_CNT AVG_ROW_LEN
-------- ---------- ------------ ---------- ---------- -----------
1000000 8617 87 1775 0 119
SQL> exec show_space('BI_TEST5')
Unformatted Blocks ..................... 240
FS1 Blocks (0-25) ..................... 1
FS2 Blocks (25-50) ..................... 1
FS3 Blocks (50-75) ..................... 0
FS4 Blocks (75-100)..................... 51
Full Blocks ..................... 8,324
Total Blocks............................ 8,704
Total Bytes............................. 142,606,336
Total MBytes............................ 136
Unused Blocks........................... 0
Unused Bytes............................ 0
Last Used Ext FileId.................... 4
Last Used Ext BlockId................... 227,072
Last Used Block......................... 512
PL/SQL-Prozedur erfolgreich abgeschlossen.
SQL> select 8324 + 51 + 1 + 1 + 240 from dual;
8324+51+1+1+240
---------------
8617
Das wären dann wieder die Blocks aus user_tables - dafür passen die "Unused Blocks" aber nicht mehr zu den EMPTY_BLOCKS, die ANALYZE ermittelt hat. Und wieder bleibt eine Differenz von 87, die aber vermutlich gar nichts mit der anderen 87 zu tun hat.
Keine Kommentare:
Kommentar veröffentlichen