A recent question on the OTN database forum:
Can any one please point to me a document or a way to calculate the average number of rows per block in oralce 10.2.0.3
One answer would be to collect stats and then approximate as block / avg_row_len – although you have to worry about things like row overheads, the row directory, and block overheads before you can be sure you’ve got it right. On top of this, the average might not be too helpful anyway. So here’s another (not necessarily fast) option that gives you more information about the blocks that have any rows in them (I picked the source$ table from a 10g system because source$ is often good for some extreme behaviour).
break on report compute sum of tot_blocks on report compute sum of tot_rows on report column avg_rows format 999.99 select twentieth, min(rows_per_block) min_rows, max(rows_per_block) max_rows, sum(block_ct) tot_blocks, sum(row_total) tot_rows, round(sum(row_total)/sum(block_ct),2) avg_rows from ( select ntile(20) over (order by rows_per_block) twentieth, rows_per_block, count(*) block_ct, rows_per_block * count(*) row_total from ( select fno, bno, count(*) rows_per_block from ( select dbms_rowid.rowid_relative_fno(rowid) as fno, dbms_rOwId.rowid_block_number(rowid) as bno from source$ ) group by fno, bno ) group by rows_per_block order by rows_per_block ) group by twentieth order by twentieth ;
I’ve used the ntile() function to split the results into 20 lines, obviously you might want to change this according to the expected variation in rowcounts for your target table. In my case the results looked like this:
TWENTIETH MIN_ROWS MAX_ROWS TOT_BLOCKS TOT_ROWS AVG_ROWS
---------- ---------- ---------- ---------- ---------- --------
1 1 11 2706 3470 1.28
2 12 22 31 492 15.87
3 23 34 30 868 28.93
4 35 45 20 813 40.65
5 46 57 13 664 51.08
6 59 70 18 1144 63.56
7 71 81 23 1751 76.13
8 82 91 47 4095 87.13
9 92 101 79 7737 97.94
10 102 111 140 14976 106.97
11 112 121 281 32799 116.72
12 122 131 326 41184 126.33
13 132 141 384 52370 136.38
14 142 151 325 47479 146.09
15 152 161 225 35125 156.11
16 162 171 110 18260 166.00
17 172 181 58 10207 175.98
18 182 191 18 3352 186.22
19 193 205 22 4377 198.95
20 206 222 16 3375 210.94
---------- ----------
sum 4872 284538
Of course, the moment you see a result like this it prompts you to ask more questions.
Is the “bell curve” effect that you can see centred around the 13th ntile indicative of a normal distribution of row lengths – if so why is the first ntile such an extreme outlier – is that indicative of a number of peculiarly long rows, did time of arrival have a special effect, is it the result of a particular pattern of delete activity … and so on.
Averages are generally very bad indicators if you’re worried about the behaviour of an Oracle system.

hi Jonathan,
while we are on this matter of rows per block , I was wondering how did you calculate that you could get 1 row per block using pct_free 99 from you buffer flush arcticle from the link below
http://jonathanlewis.wordpress.com/2011/03/16/buffer-flush/
Comment by eric — April 7, 2011 @ 6:10 am UTC Apr 7,2011 |
Eric,
I was using 8KB blocks, so there’s a block overhead of a couple of hundred bytes, giving 8,000 bytes space. 1% (i.e.100 – 99) of 8,000 is 80, so all I need is a row over about 80 bytes length to fill a block declared with pctfree 99. In fact I think I used varchar2(1000) for the row, varchar2(100) would have been easily sufficient.
Comment by Jonathan Lewis — April 7, 2011 @ 6:42 am UTC Apr 7,2011 |