
好的,我们来详细解析 ORA-00100 错误。
📌 ORA-00100 错误详解
错误信息结构组成
标准的 ORA-00100 错误信息格式如下:
ORA-00100: no memory available for allocating <number> bytes in shared pool '<pool_name>', '<reason>'
其结构可以分解为:
ORA-00100: Oracle 数据库错误的唯一标识码。no memory available for allocating <number> bytes: 错误的核心描述,表明无法在目标池中分配指定大小的内存块。<number>是请求分配的字节数。in shared pool '<pool_name>': 指明了发生分配失败的内存区域,通常是共享池(Shared Pool)或其子池(Subpool)。<pool_name>可能是'KGH: shared pool','sga heap(1,0)'等。'<reason>': 提供了分配失败的具体原因,这是诊断问题的关键。常见的原因包括'perm allocation'(永久分配失败),'kglsim object batch allocation'等。
错误含义与官方解释
官方解释:
- 原因 (Cause): 数据库无法从共享池(Shared Pool)中分配一块连续的内存来满足操作请求。这通常是由于共享池中存在大量碎片,或者共享池总体尺寸(
SHARED_POOL_SIZE)不足以应对当前工作负载。 - 行动 (Action): 增加
SHARED_POOL_SIZE初始化参数的值,或者通过刷新共享池(例如,执行ALTER SYSTEM FLUSH SHARED_POOL;)来清除碎片并释放内存。然而,刷新共享池会导致所有未缓存的 SQL 和 PL/SQL 对象需要重新解析,可能会引起短暂的性能下降。
核心要点:这是一个共享池内存分配失败错误。它表明数据库的共享池,这一用于缓存关键运行时数据(如 SQL 语句、PL/SQL 代码、数据字典信息等)的核心内存区域,无法找到一块足够大的连续空闲内存来满足新的请求。这本质上是内存碎片化或内存不足的问题。
产生错误的场景与原因
典型场景:
此错误发生在数据库负载较高、应用程序频繁执行大量不同的 SQL 语句(特别是未使用绑定变量的语句),或者共享池配置不合理的环境中。
具体原因与示例:
-
共享池碎片化 (Fragmentation):
这是最常见的原因。当大量不同大小的 SQL 语句被不断解析、缓存、然后老化移出(age out)时,共享池中会留下许多大小不一的“空闲内存碎片”。当需要一个较大的连续内存块(例如,加载一个大型包、解析一个非常复杂的 SQL)时,尽管总的空闲内存可能还很多,但无法找到一块足够大的连续空间,从而导致分配失败。错误中的reason常为'perm allocation'。 -
共享池尺寸不足 (Insufficient Size):
共享池的总体大小(由SHARED_POOL_SIZE参数设定)确实太小,无法容纳当前工作负载所需的所有库缓存(Library Cache)对象和数据字典缓存(Row Cache)对象。此时,即使没有严重碎片,也无法分配内存。 -
大型对象加载:
尝试加载一个极其庞大的 PL/SQL 包体、一个包含超长IN列表的 SQL 语句(例如SELECT ... WHERE id IN (1,2,3,...,10000)),或者进行需要大量内存的操作(如某些类型的查询编译),都可能直接请求一个非常大的内存块,从而触发此错误。 -
并发争用:
在非常高的并发下,多个进程同时请求共享池内存,也可能暂时性地导致分配失败。
相关原理
- 共享池 (Shared Pool):系统全局区(SGA)的关键组件之一。它主要由两部分组成:
- 库缓存 (Library Cache):缓存最近执行的 SQL 语句、PL/SQL 程序单元(过程、函数、包、触发器)的解析形式和执行计划。目的是避免重复解析(硬解析),节省 CPU 资源。
- 数据字典缓存 (Dictionary Cache / Row Cache):缓存数据字典信息(如表、列的定义、权限等),加速对数据字典的访问。
- 内存管理:共享池的内存管理采用一种堆(Heap)管理方式。内存被分配和释放后,会产生碎片。Oracle 使用一种名为“桶(Bucket)”的系统来管理不同大小的内存块,但极端情况下仍会出现碎片问题。
- LRU 算法:共享池使用 LRU(最近最少使用)算法来管理缓存的对象。当需要空间时,最久未被使用的对象会被移出(age out)以释放内存。但如果内存请求的速度超过了清理的速度,或者请求的块太大,就会失败。
相关联的其他 ORA 错误
在处理共享池和内存问题时,您可能会遇到相关错误:
- ORA-04031: unable to allocate bytes of shared memory (…): 这是与 ORA-00100 最为相关且更常见的错误。它也表示共享池分配失败。许多情况下,ORA-00100 可以被看作是 ORA-04031 的一种更具体的表现形式或前兆。
- ORA-00371: not enough shared pool memory: 与 ORA-00100 类似,但通常与特定的池(如 Log Buffer)相关。
- ORA-00600: internal error code: 某些严重的内部错误也可能由内存分配问题引发。
问题定位与诊断分析
当遇到 ORA-00100 时,诊断目标是确认是碎片化还是容量问题。
诊断步骤:
-
检查错误信息细节:首先记录下错误信息中的
<number>(请求大小)和'<reason>'(失败原因)。 -
查询共享池空闲内存信息:使用
V$SGASTAT视图查看共享池的可用内存情况,特别是最大连续空闲块的大小。SELECT * FROM V$SGASTAT WHERE pool = 'shared pool' AND name = 'free memory' ORDER BY bytes DESC;关注
BYTES最大的那一行,它代表了最大的一块连续空闲内存。如果这个值远小于错误信息中请求的<number>字节,那么碎片化是主要原因。如果所有free memory的总和都很小,那么容量不足是主要原因。 -
检查共享池大小和利用率:
-- 查看共享池配置大小 SHOW PARAMETER shared_pool_size; -- 查看共享池建议(如果STATISTICS_LEVEL=TYPICAL/ALL) SELECT shared_pool_size_for_estimate AS "Size (MB)", estd_lc_time_saved_factor AS "Time Saved Factor" FROM V$SHARED_POOL_ADVICE;如果
"Time Saved Factor"在更大的"Size (MB)"下显著提高,说明增大共享池有益。 -
检查 Library Cache 和 SQL 情况:
-- 查看硬解析率 SELECT name, value FROM V$SYSSTAT WHERE name IN ('parse count (hard)', 'parse count (total)'); -- 查看是否存在大量类似的SQL(可能未使用绑定变量) SELECT sql_id, COUNT(*), SUBSTR(sql_text, 1, 50) FROM V$SQL GROUP BY sql_id, SUBSTR(sql_text, 1, 50) HAVING COUNT(*) > 100 ORDER BY COUNT(*) DESC;高硬解析率和大量仅字面值不同的 SQL 是共享池压力和碎片化的主要元凶。
解决方案与步骤
解决此错误的流程是:应急处理 -> 根治优化。
步骤与示例:
-
应急处理(治标):
-
刷新共享池:立即行动,清除碎片。注意:这会清除所有缓存的SQL和PL/SQL,导致后续语句需要硬解析,可能引起短暂性能波动。
ALTER SYSTEM FLUSH SHARED_POOL;执行后,之前失败的操作通常可以成功。
-
临时增加共享池大小:如果刷新后问题很快复现,可以考虑临时增大共享池。
ALTER SYSTEM SET shared_pool_size = <new_size_in_bytes>; -- 例如 2G -- 或者 ALTER SYSTEM SET shared_pool_size = 2G;
-
-
长期优化(治本):
- 应用优化(最重要!):强制使用绑定变量。这是减少共享池压力、避免碎片化的最有效手段。将应用代码中的字面值SQL改为使用参数化查询(如
WHERE id = :1)。 - 调整共享池大小:根据
V$SHARED_POOL_ADVICE的建议,永久性地调整SHARED_POOL_SIZE参数到合适的值。 - 使用保留池 (Optional):对于需要分配大块内存的罕见操作,可以配置
SHARED_POOL_RESERVED_SIZE参数,预留一部分空间给大请求,防止它们干扰主共享池。 - 使用
CURSOR_SHARING参数 (谨慎使用):作为一个临时补救措施,可以将CURSOR_SHARING设置为FORCE或SIMILAR(较老版本),让Oracle自动将字面值替换为系统生成的绑定变量。但这可能改变执行计划,需进行严格测试。ALTER SYSTEM SET cursor_sharing = FORCE;
- 应用优化(最重要!):强制使用绑定变量。这是减少共享池压力、避免碎片化的最有效手段。将应用代码中的字面值SQL改为使用参数化查询(如
通俗易懂的解释
想象一下共享池是一个巨大的停车场。
-
SQL语句和PL/SQL代码:就像是各种型号的汽车(小型车、轿车、SUV、大卡车)。
-
分配内存:就像是一辆车需要找一个停车位。
-
共享池碎片化:就相当于停车场里的情况:虽然还有很多空位,但它们都是零零散散的小空位。这时,来了一辆大型拖挂卡车(一个需要大内存的SQL或包),它需要连续的好几个标准车位才能停下。停车场管理员(Oracle)找不到一片足够大的连续空间,于是只好立个牌子:“错误!(ORA-00100) 无法为您的‘拖挂卡车’在‘主停车场’分配‘5个连续车位’,原因是‘没有连续空间’(‘perm allocation’)”。
-
共享池容量不足:则相当于停车场本身太小,所有车位都停满了,再来任何车都没地方停了。
为什么会有这么多小空位?
因为很多车(SQL语句)只是临时停一下(被解析执行后很快就不再使用),然后就开走了。但它们离开后留下的空位大小不一。如果一直有各种小型车、中型车进进出出,最终就会把停车场“割裂”成很多没法停大车的小空位。
解决办法就是:
- 临时清场:让停车场管理员进行一次大清场(
FLUSH SHARED_POOL),把所有车都请出去,这样拖挂卡车就能一下子占到它需要的连续车位了。但缺点是,清场后所有车都要重新排队入场,入口会暂时拥堵(硬解析增多,性能短暂下降)。 - 扩建停车场:直接扩大停车场面积(增大
SHARED_POOL_SIZE),这样即使有碎片,找到大空位的概率也更高。 - 规定车辆标准:最根本的办法!要求所有来停车的尽量开统一型号的小型车(使用绑定变量)。这样无论车怎么停、怎么走,留下的空位都差不多大,任何车都能轻松找到车位,停车场利用率最高,也几乎不会产生碎片。
总结
ORA-00100 是一个共享池内存分配失败错误,其根源在于内存碎片化或绝对容量不足。它通常由未使用绑定变量的应用设计所引发,导致共享池中充斥着大量相似但不同的 SQL 语句,从而迅速耗尽内存并产生碎片。
解决策略包括:
- 短期:使用
ALTER SYSTEM FLUSH SHARED_POOL快速缓解碎片问题。 - 长期:
- 优化应用:强制使用绑定变量,这是最重要、最有效的措施。
- 调整配置:基于建议视图适当调整共享池大小。
- 考虑备选:谨慎使用
CURSOR_SHARING或保留池作为临时方案。
理解这个错误有助于DBA和开发者从根源上优化数据库性能和应用设计,构建更稳定、高效的系统。
欢迎关注我的公众号《IT小Chen》
4424

被折叠的 条评论
为什么被折叠?



