Mittwoch, Dezember 05, 2012

Intra-Block Row Chaining für row pieces

Ein paar - relativ ungeordnete - Beobachtungen zum Intra-Block Row Chaining. Zunächst: worum handelt es sich dabei überhaupt? Im Abschnitt Row Format and Size des Concept Guides findet sich der Hinweis: Oracle Database can only store 255 columns in a row piece. Thus, if you insert a row into a table that has 1000 columns, then the database creates 4 row pieces, typically chained over multiple blocks." Das Wort "typically" deutet dabei schon an, dass mehrere row pieces durchaus auch in einem einzigen Block gespeichert werden können. Dazu ein kleines (und gekürztes) Beispiel:

-- Anlage einer Test-Tabelle mit 1000 Spalten in einem MSSM-Tablespace
create table test_chaining (
  col_1 number
, col_2 number
, col_3 number
...
, col_998 number
, col_999 number
, col_1000 number
) tablespace test_ts;

-- Insert eines einzelnen Datensatzes
insert into test_chaining values (
  1
, 2
, 3
...
, 998
, 999
, 1000
);

Also eine Tabelle mit 1000 Spalten - mehr sind nicht möglich: "ORA-01792: Höchstzahl für Spalten in einer Tabelle oder einer View ist 1000" - und einem einzigen Datensatz. Zu diesem Satz ermittle ich nun den zugehörigen Block, den ich anschließend per Dump ausgeben lasse:

select dbms_rowid.rowid_relative_fno(rowid) file_nr
     , dbms_rowid.rowid_block_number(rowid) block_nr
  from test_chaining;

alter system dump datafile 7 block 1414;

Der erstellte Block-Dump enthält (unter anderem) folgende Informationen (der Beginn des Dumps und die col-Listen sind gekürzt):

Start dump data blocks tsn: 8 file#:7 minblk 1414 maxblk 1414
...
tsiz: 0x1f68
hsiz: 0x1a
pbl: 0x0c408294
     76543210
flag=--------
ntab=1
nrow=4
frre=-1
fsbo=0x1a
fseo=0x1017
avsp=0xffd
tosp=0xffd
0xe:pti[0] nrow=4 offs=0
0x12:pri[0] offs=0x1b6c
0x14:pri[1] offs=0x176a
0x16:pri[2] offs=0x1367
0x18:pri[3] offs=0x1017
block_row_dump:
tab 0, row 0, @0x1b6c
tl: 1020 fb: -----L-- lb: 0x1  cc: 255
col  0: [ 3]  c2 08 2f
col  1: [ 3]  c2 08 30
col  2: [ 3]  c2 08 31
col  3: [ 3]  c2 08 32
...
col 252: [ 3]  c2 0a 63
col 253: [ 3]  c2 0a 64
col 254: [ 2]  c2 0b
tab 0, row 1, @0x176a
tl: 1026 fb: -------- lb: 0x1  cc: 255
nrid:  0x01c00586.0
col  0: [ 3]  c2 05 5c
col  1: [ 3]  c2 05 5d
col  2: [ 3]  c2 05 5e
col  3: [ 3]  c2 05 5f
...
col 252: [ 3]  c2 08 2c
col 253: [ 3]  c2 08 2d
col 254: [ 3]  c2 08 2e
tab 0, row 2, @0x1367
tl: 1027 fb: -------- lb: 0x1  cc: 255
nrid:  0x01c00586.1
col  0: [ 3]  c2 03 25
col  1: [ 3]  c2 03 26
col  2: [ 3]  c2 03 27
col  3: [ 3]  c2 03 28
...
col 252: [ 3]  c2 05 59
col 253: [ 3]  c2 05 5a
col 254: [ 3]  c2 05 5b
tab 0, row 3, @0x1017
tl: 848 fb: --H-F--- lb: 0x1  cc: 235
nrid:  0x01c00586.2
col  0: [ 2]  c1 02
col  1: [ 2]  c1 03
col  2: [ 2]  c1 04
col  3: [ 2]  c1 05
...
col 232: [ 3]  c2 03 22
col 233: [ 3]  c2 03 23
col 234: [ 3]  c2 03 24
end_of_block_dump
End dump data blocks tsn: 8 file#: 7 minblk 1414 maxblk 1414

Offensichtlich enthält der Block also 4 row pieces, von denen die ersten drei jeweils 255 Spalten umfassen, während das vierte nur 235 Spalten enthält. Interessant ist dabei auch, dass dieses vierte Stück offenbar die ersten Spalten ab col_1 enthält (was man am Inhalt c1 02 => 1 zu erkennen ist). Hemant Chitale hat vor einigen Jahren zwei Artikel zum Thema in seinem Blog veröffentlicht und dort auch ein paar Beobachtungen zu den zugehörigen Angaben in v$sesstat (bzw. v$mystat) vermerkt. Außerdem findet sich dort ein Verweis auf einen Oracle-L thread, in dem die Herren Poder und Antognini wichtige Ergänzungen liefern. Und wenn ich schon dabei bin hier noch ein paar Links:
  • Jonathan Lewis: Analyze this! liefert Informationen zum CHAIN_CNT, der migrated und chained rows umfasst, aber intra-row-chaining nicht vermerkt; nach einem ANALYZE TABLE test_chaining COMPUTE STATISTICS; bleibt der CHAIN_CNT = 0, was insofern plausibel ist, da die Verkettung nicht block-übergreifend ist
  • Tanel Poder: Detect chained and migrated rows in Oracle – Part 1; einen Part 2 habe ich nicht gefunden ...; darin wird die Semantik der Statistiken table fetch by rowid ("how many times Oracle took a ROWID (for example from an index) and went to a table to lookup the actual row") und table fetch continued row ("when we didn’t find all that we wanted from the original row piece and had to follow a pointer to the new location of the migrated row (or next row piece of a chained row)") erläutert.
Ausgehend von den Ausführungen des Herrn Poder noch ein kleiner Versuch:

select col_1 from TEST_CHAINING;
select col_500 from TEST_CHAINING;
select col_1000 from TEST_CHAINING;

-- v$sesstat:
NAME                                   COL_1  COL_500  COL_1000 
-------------------------------------- -----  -------  --------
session logical reads                     10       12        13
consistent gets from cache                10       12        13
consistent gets                           10       12        13
consistent gets from cache (fastpath)      7        9        10
table scan blocks gotten                   5        5         4
no work - consistent read gets             5        7         8
table scan rows gotten                     4        4         4
buffer is not pinned count                 2        4         5
table fetch by rowid                       1        1         1
table scans (short tables)                 1        1         1

Daraus ziehe ich im Moment nur zwei Schlüsse:
  • Intra-Block Row Chaining wird nicht als table fetch continued row vermerkt (ist also auch in dieser Perspektive kein "echtes" Chaining)
  • die erforderliche Arbeit unterscheidet sich für den Zugriff auf die erste, eine mittlere bzw. die letzte Spalte der Tabelle deutlich - und sie erhöht sich für weiter hinten liegende Spalten
Ich gebe zu: mal wieder mangelt es meinen Ausführungen an Struktur. Vielleicht sollte ich doch mal dazu übergehen meine Gedanken zu ordnen, ehe ich etwas schreibe...

Keine Kommentare:

Kommentar veröffentlichen