Trabajo con SQL Server y Oracle. Probablemente hay algunas excepciones, pero para esas plataformas la respuesta general es que los datos e índices se actualizarán al mismo tiempo.
Creo que sería útil establecer una distinción entre cuándo se actualizan los índices para la sesión propietaria de la transacción y para otras sesiones. Por defecto, otras sesiones no verán los índices actualizados hasta que se confirme la transacción. Sin embargo, la sesión propietaria de la transacción verá inmediatamente los índices actualizados.
Para una manera de pensarlo, considere en una mesa con una clave primaria. En SQL Server y Oracle, esto se implementa como un índice. La mayoría de las veces queremos que haya un error inmediatamente si INSERT
se hace algo que violaría la clave primaria. Para que eso suceda, el índice debe actualizarse al mismo tiempo que los datos. Tenga en cuenta que otras plataformas, como Postgres, permiten restricciones diferidas que se verifican solo cuando se confirma la transacción.
Aquí hay una demostración rápida de Oracle que muestra un caso común:
CREATE TABLE X_TABLE (PK INT NULL, PRIMARY KEY (PK));
INSERT INTO X_TABLE VALUES (1);
INSERT INTO X_TABLE VALUES (1); -- no commit
La segunda INSERT
declaración arroja un error:
Error de SQL: ORA-00001: violación exclusiva (XXXXXX.SYS_C00384850) violada
00001.
00000 - "restricción única (% s.% S) violada"
* Causa: una instrucción UPDATE o INSERT intentó insertar una clave duplicada. Para Trusted Oracle configurado en modo DBMS MAC, puede ver este mensaje si existe una entrada duplicada en un nivel diferente.
* Acción: elimine la restricción única o no inserte la clave.
Si prefiere ver una acción de actualización de índice a continuación, hay una demostración simple en SQL Server. Primero cree una tabla de dos columnas con un millón de filas y un índice no agrupado en la VAL
columna:
DROP TABLE IF EXISTS X_TABLE_IX;
CREATE TABLE X_TABLE_IX (
ID INT NOT NULL,
VAL VARCHAR(10) NOT NULL
PRIMARY KEY (ID)
);
CREATE INDEX X_INDEX ON X_TABLE_IX (VAL);
-- insert one million rows with N from 1 to 1000000
INSERT INTO X_TABLE_IX
SELECT N, N FROM dbo.Getnums(1000000);
La siguiente consulta puede usar el índice no agrupado porque el índice es un índice de cobertura para esa consulta. Contiene todos los datos necesarios para ejecutarlo. Como se esperaba, no se devuelven devoluciones.
SELECT *
FROM X_TABLE_IX
WHERE VAL = 'A';
Ahora comencemos una transacción y actualicemos VAL
para casi todas las filas de la tabla:
BEGIN TRANSACTION
UPDATE X_TABLE_IX
SET VAL = 'A'
WHERE ID <> 1;
Aquí está parte del plan de consulta para eso:
En un círculo rojo está la actualización del índice no agrupado. En un círculo azul está la actualización del índice agrupado, que es esencialmente los datos de la tabla. Aunque la transacción no se ha confirmado, vemos que los datos y el índice se actualizan en parte de la ejecución de la consulta. Tenga en cuenta que no siempre verá esto en un plan dependiendo del tamaño de los datos involucrados junto con posiblemente otros factores.
Con la transacción aún no confirmada, revisemos la SELECT
consulta desde arriba.
SELECT *
FROM X_TABLE_IX
WHERE VAL = 'A';
El optimizador de consultas aún puede usar el índice y esta vez estima que se devolverán 999999 filas. La ejecución de la consulta devuelve el resultado esperado.
Esa fue una demostración simple, pero espero que aclare un poco las cosas.
Como comentario aparte, conozco algunos casos en los que se podría argumentar que un índice no se actualiza de inmediato. Esto se hace por razones de rendimiento y el usuario final no debería poder ver datos inconsistentes. Por ejemplo, a veces las eliminaciones no se aplicarán completamente a un índice en SQL Server. Se ejecuta un proceso en segundo plano y finalmente limpia los datos. Puedes leer sobre registros de fantasmas si tienes curiosidad.
Mi experiencia es que la inserción de 1,000,000 de filas realmente requerirá más recursos y tardará más en completarse que si usara insertos por lotes. Esto podría implementarse, como ejemplo, en 100 insertos de 10,000 filas.
Esto reduce la sobrecarga de los lotes que se están insertando y, si un lote falla, es una reversión más pequeña.
En cualquier caso, para SQL Server hay una utilidad bcp o el comando BULK INSERT que podría usarse para hacer inserciones por lotes.
Y, por supuesto, también puede implementar su propio código para manejar este enfoque.
fuente