Gon*_*o.- 4 oracle database-size
我必须做一些项目并且需要估计数据库大小。我将在项目中使用 Oracle,因为我们将有大量事务和数据。但是在“演示”中,我需要指定 5 年后我希望数据库增长多少。
所以,我有一个 PDF 计算行大小和其他东西的方式,但对于 SQL-Server。我想为 Oracle 做这件事。
pdf 是一个估计公式 - 没有真正的数据库,所以我不能查询数据库来检查实际大小(这是我在其他帖子中看到的,当我用谷歌搜索时)。
SQL-Server 行的公式是
Row_Size = Fixed_Data_Size +Variable_Data_Size +Null_Bitmap + 4
这个公式也适用于 Oracle 吗?另外,“4”是一行标题的大小(不知道英文怎么翻译)
因此,我必须在 Oracle 中执行此操作。Oracle 中的值 4 是多少?我认为我认为我已经解决了其他事情。
Jus*_*ave 14
理想情况下,您将创建数据库、加载一些示例数据、测量大小并进行推断。也就是说,到目前为止,估计 5 年内数据库大小的更准确方法。
如果您确实想计算数据库大小,通常首先要确定单个块中可以容纳多少行。为简单起见,我们假设行永远不会被删除,并且更新永远不会改变行的大小。我们还将假设没有使用压缩。否则,事情会变得有点(更)复杂。
计算行中数据的大小。对于固定大小的数据类型(即DATE
, CHAR
),这只是类型的大小。对于可变大小的数据类型(即NUMBER
, VARCHAR2
),这是列中数据的平均大小。有几个字节的额外开销,但您可以非常安全地忽略它——在估计实际数据的大小和随后估计每个块的行数时,它们将被错误淹没。
如果您期望每行将有 x 字节的数据,则每个块的行数将为
<<rows per block>> =
floor( <<database block size>> *
(1 - <<pctfree of table>>/100) /
<<size of row>> ) + 1
Run Code Online (Sandbox Code Playgroud)
假设一行小于<<database block size>> * <<pctfree of table>>/100
. 如果该行较大,则不要将floor
.
一旦知道每个块的行数,表的估计大小将是
<<size of table>> =
ceil( <<number of rows in table>> / <<rows per block>> ) *
<<database block size>>
Run Code Online (Sandbox Code Playgroud)
浏览一个例子
我的数据库块大小是 8k,我们假设我使用的是默认值PCTFREE
10(这意味着 10% 的块保留用于将来增加行大小的更新)。我将创建一个简单的两列表
SQL> create table foo(
2 foo_id number,
3 foo_str varchar2(100)
4 );
Table created.
Run Code Online (Sandbox Code Playgroud)
如果foo_id
将成为值为 1 到 100 万的主键,则每个foo_id
将消耗 1 到 7 个字节的空间。但我也从测试中了解到,平均而言,它需要大约 6 个字节(实际上是 5.89 个字节)。当然,foo_id
值越大,平均每个foo_id
需要的空间就越大。Oracle 平均每个元素需要 1.1 字节来存储数字 1-10,1.92 字节来存储 1-100,2.89 字节来存储 1-1,000,3.89 字节来存储 1-10,000,4.89 字节来存储 1-100,000,以及5.89 字节存储 1-1,000,000。因此,让我们估计我们的示例foo_id
需要 6 个字节,并且foo_str
需要 50 个字节,因为平均值foo_str
大约为 50 个字节。因此,我们将估计 56 字节的行大小。
每个块的行数
<<rows per block>> =
floor( 8192 *
(1 - 10/100) /
56 ) + 1
Run Code Online (Sandbox Code Playgroud)
每块 132 行。如果我们要估算一个 100 万行的表的大小,
<<size of table>> =
ceil( 1000000 / 132 ) *
8192
Run Code Online (Sandbox Code Playgroud)
结果为 59.19 MB。
现在,让我们测试一下我们的估计
我们将插入 100 万行,foo_id
从 1 到 1,000,000,foo_str
是一个随机长度在 1 到 100 之间的字符串。
SQL> ed
Wrote file afiedt.buf
1 insert into foo
2 select level, dbms_random.string( 'p', dbms_random.value(1,100))
3 from dual
4* connect by level <= 1000000
SQL> /
1000000 rows created.
Run Code Online (Sandbox Code Playgroud)
我们对平均行长度的估计是正确的(请注意,实际上,您不会如此接近——您对可变列大小的估计不会那么准确)
SQL> exec dbms_stats.gather_table_stats( 'SCOTT', 'FOO' );
PL/SQL procedure successfully completed.
SQL> ed
Wrote file afiedt.buf
1 select avg_row_len, num_rows
2 from user_tables
3* where table_name = 'FOO'
SQL> /
AVG_ROW_LEN NUM_ROWS
----------- ----------
56 1000000
Run Code Online (Sandbox Code Playgroud)
但实际的桌子有多大?最常用的方法是查看 72 MB 的段大小。
SQL> select sum(bytes)/1024/1024 mb
2 from user_segments
3 where segment_name = 'FOO';
MB
----------
72
Run Code Online (Sandbox Code Playgroud)
我们的猜测偏离了大约 20%,那时我们对行大小的估计是完美的。这是因为 Oracle 将空间分配给我们忽略的称为范围的块中的表。对此有不同的算法,这取决于表空间的设置。假设所有表都在本地管理的表空间中的最新 Oracle 版本,您将在统一范围分配和自动范围分配之间进行选择。在我的示例中,我使用的表空间使用自动范围分配。反过来,确切的算法可能取决于您使用的 Oracle 版本。但是,在我的情况下,前 16 个范围是 64 kb,接下来的 63 个范围是 1 MB,最后一个范围是 8 MB
SQL> ed
Wrote file afiedt.buf
1 select bytes, count(*)
2 from user_extents
3 where segment_name = 'FOO'
4 group by bytes
5* order by bytes
SQL> /
BYTES COUNT(*)
---------- ----------
65536 16
1048576 63
8388608 1
Run Code Online (Sandbox Code Playgroud)
这意味着我可能有点不走运,我的数据比总共 64 MB 的 79 个盘区多一点,所以我不得不分配大小为 8 MB 的第 80 个盘区,总共 72 MB。我们可以使用dbms_space 包来获取有关正在使用多少空间的更多详细信息。当我们这样做时,我们看到我们实际上只使用了已分配的 72 MB 中的 66.22 MB。所以我们的实际估计误差真的只有~10%
SQL> ed
Wrote file afiedt.buf
1 DECLARE
2 l_space_used NUMBER;
3 l_space_allocated NUMBER;
4 l_chained_pct NUMBER;
5 BEGIN
6 dbms_space.object_space_usage(
7 'SCOTT',
8 'FOO',
9 'TABLE',
10 NULL,
11 l_space_used,
12 l_space_allocated,
13 l_chained_pct);
14 dbms_output.put_line('Space Used: ' || TO_CHAR(round(l_space_used/1024/1024,2)) || ' MB');
15 dbms_output.put_line('Space Allocated: ' || TO_CHAR(l_space_allocated/1024/1024) || ' MB');
16 dbms_output.put_line('Chained Percentage: ' || TO_CHAR(l_chained_pct));
17* END;
SQL> /
Space Used: 66.22 MB
Space Allocated: 72 MB
Chained Percentage: 0
PL/SQL procedure successfully completed.
Run Code Online (Sandbox Code Playgroud)
有捷径吗?
如果您使用的是最新版本的 Oracle,则可以使用该dbms_space.create_table_cost
过程来估计表的大小。有几种方法可以做到这一点。第一个选项是传入行的大小。使用我们的 56 字节估计,产生 64 MB 的表大小估计,使用 63.52 MB,非常接近
SQL> ed
Wrote file afiedt.buf
1 DECLARE
2 l_used_bytes NUMBER;
3 l_allocated_bytes NUMBER;
4 BEGIN
5 dbms_space.create_table_cost('USERS',
6 56,
7 1000000,
8 10,
9 l_used_bytes,
10 l_allocated_bytes);
11 dbms_output.put_line('Used Bytes: ' || TO_CHAR(round(l_used_bytes/1024/1024,2)) || ' MB');
12 dbms_output.put_line('Alloc Bytes: ' || TO_CHAR(l_allocated_bytes/1024/1024) || ' MB');
13* END;
SQL> /
Used Bytes: 63.52 MB
Alloc Bytes: 64 MB
PL/SQL procedure successfully completed.
Run Code Online (Sandbox Code Playgroud)
您还可以指定将在您的表中的列的数据类型。但是,由于无法指定平均大小,因此这往往不如自己做准确。但是,在我们的例子中,这非常好,因为我们的VARCHAR2
列碰巧填充了平均为列最大大小一半的字符串。但是,在我们的例子中,它正确估计了 72 MB 的分配大小,使用了 67.94 MB。
SQL> ed
Wrote file afiedt.buf
1 DECLARE
2 l_used_bytes NUMBER;
3 l_allocated_bytes NUMBER;
4 l_cols sys.create_table_cost_columns;
5 BEGIN
6 l_cols := sys.create_table_cost_columns(
7 sys.create_table_cost_colinfo('NUMBER',10),
8 sys.create_table_cost_colinfo('VARCHAR2',100));
9 dbms_space.create_table_cost('USERS',
10 l_cols,
11 1000000,
12 10,
13 l_used_bytes,
14 l_allocated_bytes);
15 dbms_output.put_line('Used Bytes: ' || TO_CHAR(round(l_used_bytes/1024/1024,2)) || ' MB');
16 dbms_output.put_line('Alloc Bytes: ' || TO_CHAR(l_allocated_bytes/1024/1024) || ' MB');
17* END;
SQL> /
Used Bytes: 67.94 MB
Alloc Bytes: 72 MB
PL/SQL procedure successfully completed.
Run Code Online (Sandbox Code Playgroud)