Me he encontrado con un problema extraño últimamente, programando en una base de datos Oracle: dentro de una transacción serializable, hago una inserción masiva (INSERTAR ... SELECCIONAR), e inmediatamente después, I abra un cursor con un SELECCIONAR en la tabla alterada. Supuse que este cursor incluiría las filas recién insertadas, pero, para mi sorpresa, su contenido es errático, a veces incluye todas las filas recién insertadas, y algunas veces solo un subconjunto.Oracle: seleccione inmediatamente después de la inserción en la transacción serializable
He resuelto este problema al comprometerme antes de abrir el cursor, pero el comportamiento me ha intrigado. ¿Se puede confiar en una selección después de una inserción dentro de la misma transacción, sin un compromiso de intervinculación? ¿O está este comportamiento relacionado de alguna manera con la transacción que se puede serializar?
Seguimiento: Al intentar crear un caso de prueba reproducible, solo pude obtener este comportamiento una vez que agregué un índice (en este caso un índice de clave principal, en el código real era un índice normal). Tal vez el problema radica en el tiempo invertido en la creación del índice, de modo que SELECT en realidad utiliza un índice incompleto para recuperar los resultados. De todos modos, aquí va un caso de prueba reproducible:
-- Create empty source table
CREATE TABLE TEST_CASE_1 AS
(SELECT 'CONTENT' AS CONTENT
FROM DUAL
WHERE 1 = 2)
-- Add primary key
ALTER TABLE TEST_CASE_1
ADD CONSTRAINT TEST_CASE_1_PK PRIMARY KEY (CONTENT);
-- Create empty destination table
CREATE TABLE TEST_CASE_2 AS
(SELECT 'CONTENT' AS CONTENT
FROM DUAL
WHERE 1 = 2)
-- Example of faulty code
BEGIN
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
-- Populate with 100.000 rows (I used ALL_OBJECTS but any source of 100.000 rows is good)
INSERT INTO TEST_CASE_1
(SELECT ROWNUM
FROM ALL_OBJECTS
WHERE ROWNUM <= 100000);
INSERT INTO TEST_CASE_2
(SELECT *
FROM TEST_CASE_1
WHERE CONTENT > 0);
COMMIT;
END;
En este ejemplo, yo esperaría TEST_CASE_2 de contar también con 100.000 filas. Al reproducir este caso de prueba (en una base de datos sin carga), obtuve alrededor de 400-500 filas insertadas. Al eliminar la declaración que establece la transacción como serializable, obtuve el conteo correcto de 100.000 filas.
¿Está abriendo el cursor en la misma sesión de la base de datos que está haciendo la inserción? ¿Dónde está haciendo este trabajo, en realidad en la base de datos o desde una aplicación cliente, y si este último tiene agrupación de conexiones, y usted (a veces) obtiene una conexión diferente para las dos acciones? –
El cursor se abre en la misma sesión. Originalmente, el cursor se abrió en la base de datos y luego se repitió en un ejecutable de .NET, pero para aislar el problema hice una versión del procedimiento que iteraba el cursor dentro de la base de datos, y el problema persistía; de hecho, antes de hacer esto no podía Me convencí a mí mismo de que el problema estaba en la selección siguiendo el inserto. – user1578874
Eso no debería suceder; desde [los documentos] (http://docs.oracle.com/cd/E11882_01/server.112/e25789/consist.htm#sthref1189) 'En el nivel de aislamiento de serialización, una transacción solo ve los cambios comprometidos en el momento de la transacción -no comienza la consulta y los cambios realizados por la transacción en sí ", por lo que debería ver sus propios cambios. Podría ser un error en tu versión específica, supongo. Comprometerse hace que cambiar el nivel de aislamiento sea un poco inútil. ¿Puedes publicar un caso de prueba reproducible? –