ITPub博客

首页 > Linux操作系统 > Linux操作系统 > INTERVAL分区插入大量数据导致ORA-4031错误

INTERVAL分区插入大量数据导致ORA-4031错误

原创 Linux操作系统 作者:yangtingkun 时间:2010-04-19 23:54:28 0 删除 编辑

对INTERVAL分区插入大量数据,使得INTERVAL分区不停产生新的分区,最终导致ORA-4031错误的产生。

 

 

本想测试一下分区表中最多可以拥有多少个分区,由于INTERVAL分区是最方便的,只需要插入数据就可以了,不需要通过程序执行大量的DDL语句,没想到数据导致了ORA-4031的错误。

SQL> SELECT * FROM V$VERSION;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
PL/SQL Release 11.2.0.1.0 - Production
CORE    11.2.0.1.0      Production
TNS for Linux: Version 11.2.0.1.0 - Production
NLSRTL Version 11.2.0.1.0 - Production

SQL> CREATE TABLE T_PART_INTER
  2  (ID NUMBER)
  3  PARTITION BY RANGE (ID)
  4  INTERVAL (1)
  5  (PARTITION P1 VALUES LESS THAN (2));

表已创建。

SQL> INSERT INTO T_PART_INTER
  2  SELECT ROWNUM
  3  FROM ALL_OBJECTS;
INSERT INTO T_PART_INTER
*
第 1 行出现错误:
ORA-04031:
无法分配 2080 字节的共享内存 ("shared pool","T_PART_INTER","PRTMV^f36d7b3","slab alloc in kksga")


SQL> SELECT COUNT(*)
  2  FROM USER_TAB_PARTITIONS
  3  WHERE TABLE_NAME = 'T_PART_INTER';

  COUNT(*)
----------
      9736

下面和ALTER TABLE ADD PARTITION语句进行对比。

为了测试,首先清空共享池:

SQL> CONN / AS SYSDBA
已连接。
SQL> ALTER SYSTEM FLUSH SHARED_POOL;

系统已更改。

下面建立一个范围分区表,通过增加分区的方式,看看是否会造成ORA-4031错误:

SQL> CONN TEST/TEST
已连接。
SQL> CREATE TABLE T_PART_RANGE
  2  (ID NUMBER)
  3  PARTITION BY RANGE (ID)
  4  (PARTITION P1 VALUES LESS THAN (2));

表已创建。

SQL> BEGIN
  2  FOR I IN 2..20000 LOOP
  3     EXECUTE IMMEDIATE 'ALTER TABLE T_PART_RANGE ADD PARTITION P'
  4             || I || ' VALUES LESS THAN (' || (I + 1) || ')';
  5  END LOOP;
  6  END;
  7  /

PL/SQL 过程已成功完成。

使用ALTER TABLE ADD PARTITION的方式,即使将分区的数量增大到20000,也不会出现ORA-4031错误。

INTERVAL分区确实使得范围分区的管理工作量大大降低,分区的创建不再需要DBA手工提前创建,也不需要在JOB中定时创建,而是等到新分区的数据进入到数据库中时,由Oracle自动创建。这种方式不但减轻了维护的工作量,而且提高的空间利用率。如果分区没有对应的数据,则分区不会被创建。

看上起确实是一举两得,但是INTERVAL分区的创建也是有代价的,在数据插入的时候建立分区,就意味着当分区需要创建时,用户的INSERT或UPDATE语句就会导致大量的递归调用来创建新的分区。对于每个分区都很大,分区创建不是很频繁的情况,这点代价不算什么,但是如果分区创建很频繁,就会导致性能的问题,上面就是一个极端的例子,每条INSERT都会导致Oracle的递归调用,进行空间分配,分区信息的维护,不仅造成性能底下,最后甚至共享池都全部耗尽了。

下面看一下共享池中哪部分占用了这些内存资源:

SQL> CONN / AS SYSDBA
已连接。
SQL> SELECT POOL, SUM(BYTES)/1024/1024
  2  FROM V$SGASTAT
  3  GROUP BY POOL;

POOL         SUM(BYTES)/1024/1024
------------ --------------------
                       98.8458252
java pool                      64
streams pool                  128
shared pool            6144.00457
large pool                     64

SQL> SHOW SGA

Total System Global Area 6814535680 bytes
Fixed Size                  2214016 bytes
Variable Size            6710888320 bytes
Database Buffers           67108864 bytes
Redo Buffers               34324480 bytes

一共6G的内存,几乎全部分配给了共享池。

下面重启一下数据库,再次执行一下上面的过程:

SQL> SHUTDOWN IMMEDIATE
数据库已经关闭。
已经卸载数据库。
ORACLE
例程已经关闭。
SQL> STARTUP
ORACLE
例程已经启动。

Total System Global Area 6814535680 bytes
Fixed Size                  2214016 bytes
Variable Size            4026533760 bytes
Database Buffers         2751463424 bytes
Redo Buffers               34324480 bytes
数据库装载完毕。
数据库已经打开。
SQL> SHOW SGA

Total System Global Area 6814535680 bytes
Fixed Size                  2214016 bytes
Variable Size            4093642624 bytes
Database Buffers         2684354560 bytes
Redo Buffers               34324480 bytes
SQL> SELECT POOL, SUM(BYTES)/1024/1024
  2  FROM V$SGASTAT
  3  GROUP BY POOL;

POOL         SUM(BYTES)/1024/1024
------------ --------------------
                       2594.84583
java pool                      64
streams pool                  128
shared pool            1024.00457
large pool                     64

可以看到,正常启动后,共享池只分配了1G的空间:

SQL> SELECT DISTINCT POOL,
  2  FIRST_VALUE(NAME) OVER(PARTITION BY POOL ORDER BY BYTES DESC) NAME,
  3  FIRST_VALUE(BYTES/1024/1024) OVER(PARTITION BY POOL ORDER BY BYTES DESC) M
  4  FROM V$SGASTAT;

POOL         NAME                                M
------------ -------------------------- ----------
large pool   free memory                   56.1875
streams pool free memory                       128
             buffer_cache                     2560
java pool    free memory                        64
shared pool  free memory                864.393021

可以看到,每个池中占用空间最大的部分都是空闲内存,其中共享池中有864M的空闲空间,下面在一个会话执行INTERVAL分区表的数据插入过程:

SQL> INSERT INTO T_PART_INTER
  2  SELECT ROWNUM
  3  FROM ALL_OBJECTS;
INSERT INTO T_PART_INTER
*
第 1 行出现错误:
ORA-04031:
无法分配 72 字节的共享内存 ("shared pool","T_PART_INTER","PRTMV^f36d7b3","kggec.c.kggfa")

在这个插入执行过程中,Oracle尚未报错的时候,在立国那一个会话查询V$SGASTAT视图,检查共享池中哪个部分占用的空间最大:

SQL> SELECT MAX(BYTES)/1024/1024 FROM V$SGASTAT
  2  WHERE POOL = 'shared pool';
SELECT MAX(BYTES)/1024/1024 FROM V$SGASTAT
                                 *
第 1 行出现错误:
ORA-04031:
无法分配 264 字节的共享内存 ("shared pool","unknown object","KGLH0^ae4fab53","kglob")
ORA-04031:
无法分配 264 字节的共享内存 ("shared pool","unknown object","KGLH0^75c1a12f","kglob")


SQL> SELECT DISTINCT POOL,
  2  FIRST_VALUE(NAME) OVER(PARTITION BY POOL ORDER BY BYTES DESC) NAME,
  3  FIRST_VALUE(BYTES/1024/1024) OVER(PARTITION BY POOL ORDER BY BYTES DESC) M
  4  FROM V$SGASTAT;

POOL         NAME                                M
------------ -------------------------- ----------
large pool   free memory                   56.1875
shared pool  PRTMV                      4994.42047
streams pool free memory                       128
java pool    free memory                        64
             buffer_cache                       64

SQL> SELECT DISTINCT POOL,
  2  FIRST_VALUE(NAME) OVER(PARTITION BY POOL ORDER BY BYTES DESC) NAME,
  3  FIRST_VALUE(BYTES/1024/1024) OVER(PARTITION BY POOL ORDER BY BYTES DESC) M
  4  FROM V$SGASTAT;
FROM V$SGASTAT
     *
第 4 行出现错误:
ORA-04031:
无法分配 264 字节的共享内存 ("shared pool","unknown object","KGLH0^ae4fab53","kglob")
ORA-04031:
无法分配 264 字节的共享内存 ("shared pool","unknown object","KGLH0^75c1a12f","kglob")

查询很多时候是返回ORA-4031错误,但是有时能返回结果,在上面的查询结果中,PRTMV占用了共享池中将近5G的空间,而DB_CACHE已经缩小到了64M。

SQL> SELECT DISTINCT POOL,
  2  FIRST_VALUE(NAME) OVER(PARTITION BY POOL ORDER BY BYTES DESC) NAME,
  3  FIRST_VALUE(BYTES/1024/1024) OVER(PARTITION BY POOL ORDER BY BYTES DESC) M
  4  FROM V$SGASTAT;

POOL         NAME                                M
------------ -------------------------- ----------
large pool   free memory                   56.1875
streams pool free memory                       128
java pool    free memory                        64
             buffer_cache                       64
shared pool  PRTMV                      4993.20631

SQL> SELECT POOL, SUM(BYTES)/1024/1024
  2  FROM V$SGASTAT
  3  GROUP BY POOL;

POOL         SUM(BYTES)/1024/1024
------------ --------------------
                       98.8458252
java pool                      64
streams pool                  128
shared pool            6144.00457
large pool                     64

等到插入语句返回ORA-4031错误后,再次运行查询语句,可以看到,6G的共享池中5G的空间被PRTMV占用。查询了一下,没有发现关于这个内存区域的说明,怀疑是11g中为了支持INTERVAL分区而新增的内存区。

虽然每个分区一条记录的设计确实不合理,但是Oracle的INTERVAL分区内存使用也存在一定的问题。不然不会仅不到10000个分区,就耗尽了6G的内存。

 

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/4227/viewspace-660180/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
暂无介绍

注册时间:2007-12-29

  • 博文量
    1964
  • 访问量
    11074992