imp STATISTICS=y的陷阱

August 3rd, 2009 | Categories: Boring | Tags:

今天一个数据库被查出有很多literal SQL,有6000多条。都是来自imp.

SQL_TEXT                                        COUNT(*)               MODULE
———————————— ————————
DECLARE SREC DBMS_STATS.STA        6006      imp@MACHINE (TNS V1-V3)

Literal SQL的文本如下,都是在设置导入表相应的统计信息。这个表不但有很多列,而且有很多分区和子分区。列*分区,就有6000条的literal SQL.

SQL_TEXT
—————————————————————-
DECLARE SREC DBMS_STATS.STATREC; BEGIN SREC.MINVAL := NULL; SREC.MAXVAL := NULL; SREC.EAVS := 0;
SREC.CHVALS := NULL; SREC.NOVALS := DBMS_STATS.NUMARRAY(0,0); SREC.BKVALS := DBMS_STATS.NUMARRAY(0,1);
SREC.EPC := 2; DBMS_STATS.SET_COLUMN_STATS(NULL,’”TEST”‘,’”FLAG_5″‘,’”PART44_SUBPARTMAX”‘,
NULL,NULL,0,0,0,srec,0,6); END;

察看这些literal SQL占用内存的情况

SQL> select sum(SHARABLE_MEM)/power(1024,2) SHARABLE_MEM,sum(PERSISTENT_MEM)/power(1024,2) PERSISTENT_MEM,sum(RUNTIME_MEM)/power(1024,2)
RUNTIME_MEM from v$sql where sql_text like ‘DECLARE SREC DBMS_STATS.STATREC; BEGIN SREC.MINVAL := NULL;%’;

SHARABLE_MEM PERSISTENT_MEM RUNTIME_MEM
———— ————– ———–
105.5 6.1                      1.8

三个数值似乎都不高,但从statspack里面我看到IMP那个时候shared pool free memory大概降低了200M。还好我就导入一个表。要是导入的表很多而Shared pool free memory又不多的情况下,说不定会很引起很严重的Shared pool contention。

这些literal SQL在10g中也不好manually remove,11g的话说不定可以用dbms_shared_pool.remove。

还有一个tip是order by可以在为长时间打开的cursor避免ora-1555

通常开发者可能会open一个cursor,取一些纪录,然后对这些纪录作处理,又或者作些别的事情,然后再fetch一些纪录….. 记录多的时候,这个cursor就会open很长时间,超过undo_rentention的时候,就有可能发生ORA-1555的错误。

如果修改代码很麻烦,则我们可以在这个SQL cursor上加一个order by,让Oracle先将所有数据读出,排序,将排好顺序的纪录存储在pga或者temporary tablespace。以后再fetch cursor的时候,直接从pga中读取已排序的记录,再无需做consistent read,因此避免了ora-1555.

有时候确实想不到这个good idea.

Del.icio.us Google书签 Digg Live Bookmark Technorati Furl Yahoo书签 Facebook 百度搜藏 新浪 ViVi 365Key 网摘 天极网摘 和讯网摘 博拉网 POCO 网摘 饭否 QQ 书签 Digbuzz 我挖网 Mister Wong
  1. tp
    August 3rd, 2009 at 22:44
    Quote | #1

    ‘如果修改代码很麻烦,则我们可以在这个SQL cursor上加一个order by,让Oracle先将所有数据读出,排序’

    加了order by ,这个cursor就会在open时fetch所有数椐?
    还是说用bulk insert到temp table ?

  2. yumianfeilong
    August 3rd, 2009 at 23:05
    Quote | #2

    tp:
    加了order by ,这个cursor就会在open时fetch所有数椐?

    Open cursor后,fetch第一行的时候,因为是排序的,所以Oracle要一致读所有的记录,在pga或者temproary tablespace中排好序,然后返回第一行给客户端。再fetch接下来的行时,直接从pga或者temproary tablespace按照顺序返回记录。

  3. luzp
    August 4th, 2009 at 09:53
    Quote | #3

    加order by的主意看起来很不错。不知道能否实验证实一下?

  4. Yong Huang
    August 23rd, 2009 at 09:58
    Quote | #4

    statistics=none is almost always recommended. The same applies to impdp (the parameter is exclude=(table_statistics,index_statistics)). It has the same problem of littering the shared pool with lots of literal SQLs. See Bug 7185178. If the damage is already done, you can simply “grant select on sys.impdp_stats to dba” to remove those SQLs (in case of impdp). BTW, dbms_shared_pool.purge (not remove) is available from 10.2.0.4 and up.