ORA-1691 happens when a lob segment cannot extend itself to accommodate the growth due to new data being inserted. Usually remedies are extending the data file and adding a data file. However there's a special situation where this is the expected behavior. ORA-1691 is reported on alert log (only on alert log no client side error) when space taken by the lob segment is allocated for reuse, before the undo retention period is expired.
From the Admin Guide "Automatic tuning of undo retention is not supported for LOBs. This is because undo information for LOBs is stored in the segment itself and not in the undo tablespace. For LOBs, the database attempts to honor the minimum undo retention period specified by UNDO_RETENTION. However, if space becomes low, unexpired LOB undo information may be overwritten."
From Database Concept "The database manages read consistency for LOB segments differently from other data. Instead of using undo data to record changes, the database stores the before images in the segment itself. When a transaction changes a LOB, the database allocates a new chunk and leaves the old data in place. If the transaction rolls back, then the database rolls back the changes to the index, which points to the old chunk."
Below is the test case that illustrate the reporting of ora-1691 on the alert log. The test case create the LOB as BasicFile. But the observed behavior is same for SecureFile as well. The test was done on 11.2.0.3.7 and 11.1.0.16 on Linux.
1. Create two tablespaces one for data and one for lob segments
5. Run the java code to insert another 141 rows as before.
According to Oracle this is expected behavior and not a bug. For system where automated alert log monitoring is in place it would be difficult to distinguish if there's a space issue or not without looking into free space within the lobsegment.
One way to overcome this observed behavior is to change the undo related parameters of the LOB segment, which are pctversion and retention. Creating the table with pctversion 0 eliminate the reporting of ora-1691 on the alert log when log segment space is reused.
If space is not reused within the the undo_retention then again the ora-1691 is not observed on the alert log. There's no explicit way to change the retention value on LOB segment. It's taken from the undo_retention parameter.
Java code used for LOB insert
From the Admin Guide "Automatic tuning of undo retention is not supported for LOBs. This is because undo information for LOBs is stored in the segment itself and not in the undo tablespace. For LOBs, the database attempts to honor the minimum undo retention period specified by UNDO_RETENTION. However, if space becomes low, unexpired LOB undo information may be overwritten."
From Database Concept "The database manages read consistency for LOB segments differently from other data. Instead of using undo data to record changes, the database stores the before images in the segment itself. When a transaction changes a LOB, the database allocates a new chunk and leaves the old data in place. If the transaction rolls back, then the database rolls back the changes to the index, which points to the old chunk."
Below is the test case that illustrate the reporting of ora-1691 on the alert log. The test case create the LOB as BasicFile. But the observed behavior is same for SecureFile as well. The test was done on 11.2.0.3.7 and 11.1.0.16 on Linux.
1. Create two tablespaces one for data and one for lob segments
SQL> create tablespace datatbs datafile '+data(datafile)' size 5m autoextend on next 1m maxsize 10m;2. Create the table with a LOB column and make sure data segments and lob segments are created in the correct tablespaces
SQL> create tablespace lobtbs datafile '+data(datafile)' size 5m autoextend on next 1m maxsize 10m;
CREATE TABLE lobtest ( ID number, "OBJECT" BLOB ) SEGMENT CREATION IMMEDIATE TABLESPACE datatbs3. The java code given at the end of the post is used to populate the table. The java code will insert a integer and a 50K BLOB.
LOB ( "OBJECT" )
STORE AS object_lob_seg ( TABLESPACE lobtbs
DISABLE STORAGE IN ROW
CHUNK 8K
CACHE
INDEX object_lob_idx (TABLESPACE lobtbs)
);
java LobReuse 192.168.0.66 1521 ent11g2 asanga asa 141Here (192.168.0.66 1521 ent11g2) is the (DB Server name or IP, listener port, SID) and next two parameters (asanga asa) is (username, password) and last parameter 141 is number of inserts. Verify 141 rows are inserted
SQL> select count(*) from lobtest;141 is the maximum number of inserts that could be made before the 10m maximum size is reached on the LOBTBS tablespace. Trying to insert any more rows would result in ora-1691 on client side which is the expected behavior (this is not the reason for the post).
COUNT(*)
----------
141
java LobReuse 192.168.0.66 1521 ent11g2 asanga asa 1and following lines will be reported on the alert log
java.sql.SQLException: ORA-01691: unable to extend lob segment ASANGA.OBJECT_LOB_SEG by 128 in tablespace LOBTBS
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:445)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:396)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:879)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:450)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:192)
ORA-1691: unable to extend lobsegment ASANGA.OBJECT_LOB_SEG by 128 in tablespace LOBTBS4. Delete all the inserted rows and verify no rows are in the table.
ORA-1691: unable to extend lobsegment ASANGA.OBJECT_LOB_SEG by 128 in tablespace LOBTBS
ORA-1691: unable to extend lobsegment ASANGA.OBJECT_LOB_SEG by 128 in tablespace LOBTBS
SQL> delete from lobtest;Deleting rows will not reduce the segment size (unless shrink space other space reclaimable mechanism are used to reduce the size). Once space is allocated to a segment it will remain allocated and reused if become free due to row deletion. At this stage the segment is occupying the full tablespace and there's no place to grow and for new inserts the log segment space must be reused.
141 rows deleted.
SQL> commit;
Commit complete.
SQL> select count(*) from lobtest;
COUNT(*)
----------
0
5. Run the java code to insert another 141 rows as before.
java LobReuse 192.168.0.66 1521 ent11g2 asanga asa 141This will execute without any errors and at the end of the execution 141 rows would have been inserted to the table
However if alert log was monitored during this time following could be seen
SQL> select count(*) from lobtest;
COUNT(*)
----------
141
ORA-1691: unable to extend lobsegment ASANGA.OBJECT_LOB_SEG by 128 in tablespace LOBTBSThis is misleading as no error was shown on the client side and 141 rows got inserted successful. But there's no way to verify this looking only at the alert log which looks like the segment is unable to expand and no rows got inserted. Having the Event 44951 set seem to reduce the number of lines reporting ora-1691 on alert log but still it does get reported. (Event 44951 sets number of chunks to clean up). Beside the error it enq: HW - contention waits were also observed.
ORA-1691: unable to extend lobsegment ASANGA.OBJECT_LOB_SEG by 128 in tablespace LOBTBS
ORA-1691: unable to extend lobsegment ASANGA.OBJECT_LOB_SEG by 128 in tablespace LOBTBS
ORA-1691: unable to extend lobsegment ASANGA.OBJECT_LOB_SEG by 128 in tablespace LOBTBS
ORA-1691: unable to extend lobsegment ASANGA.OBJECT_LOB_SEG by 128 in tablespace LOBTBS
ORA-1691: unable to extend lobsegment ASANGA.OBJECT_LOB_SEG by 128 in tablespace LOBTBS
According to Oracle this is expected behavior and not a bug. For system where automated alert log monitoring is in place it would be difficult to distinguish if there's a space issue or not without looking into free space within the lobsegment.
One way to overcome this observed behavior is to change the undo related parameters of the LOB segment, which are pctversion and retention. Creating the table with pctversion 0 eliminate the reporting of ora-1691 on the alert log when log segment space is reused.
CREATE TABLE lobtest ( ID number, "OBJECT" BLOB ) SEGMENT CREATION IMMEDIATE TABLESPACE datatbsHowever this may not suite every application and could lead to ora-1555 snapshot too old errors. Oracle documentation provide some guide lines on how to set pctversion value based on update/read patterns of the application.
LOB ( "OBJECT" )
STORE AS object_lob_seg ( TABLESPACE lobtbs
DISABLE STORAGE IN ROW
CHUNK 8K
CACHE
PCTVERSION 0
INDEX object_lob_idx (TABLESPACE lobtbs)
);
If space is not reused within the the undo_retention then again the ora-1691 is not observed on the alert log. There's no explicit way to change the retention value on LOB segment. It's taken from the undo_retention parameter.
Java code used for LOB insert
import java.sql.Connection;
import oracle.jdbc.OraclePreparedStatement;
import oracle.jdbc.pool.OracleDataSource;
/**
*
* @author Asanga
*/
public class LobReuse {
public static void main(String[] args) {
try {
OracleDataSource pool = new OracleDataSource();
pool.setURL("jdbc:oracle:thin:@"+args[0]+":"+args[1]+":"+args[2]);
pool.setUser(args[3]);
pool.setPassword(args[4]);
int inserts = Integer.parseInt(args[5]);
for(int i = 0 ; i < inserts ; i++){
Connection con = pool.getConnection();
con.setAutoCommit(false);
byte[] x = new byte[50 * 1024];
x[1]=10; x[40 * 1024] = 20;
OraclePreparedStatement pr = (OraclePreparedStatement) con.prepareStatement("insert into lobtest values(?,?)");
pr.setInt(1, i );
pr.setBytes(2, x);
pr.execute();
con.commit();
pr.close();
con.close();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}}