Eu trabalho com SQL Server e Oracle. Provavelmente existem algumas exceções, mas para essas plataformas a resposta geral é que dados e índices serão atualizados ao mesmo tempo.
Eu acho que seria útil fazer uma distinção entre quando os índices são atualizados para a sessão que possui a transação e para outras sessões. Por padrão, outras sessões não verão os índices atualizados até que a transação seja confirmada. No entanto, a sessão que possui a transação verá imediatamente os índices atualizados.
Para uma maneira de pensar sobre isso, considere em uma mesa com uma chave primária. No SQL Server e Oracle, isso é implementado como um índice. Na maioria das vezes, queremos que ocorra imediatamente um erro se INSERT
for feito, o que violaria a chave primária. Para que isso aconteça, o índice deve ser atualizado ao mesmo tempo que os dados. Observe que outras plataformas, como o Postgres, permitem restrições adiadas que são verificadas apenas quando a transação é confirmada.
Aqui está uma demonstração rápida do Oracle, mostrando um caso comum:
CREATE TABLE X_TABLE (PK INT NULL, PRIMARY KEY (PK));
INSERT INTO X_TABLE VALUES (1);
INSERT INTO X_TABLE VALUES (1); -- no commit
A segunda INSERT
instrução gera um erro:
Erro SQL: ORA-00001: restrição exclusiva (XXXXXX.SYS_C00384850) violada
00001.
00000 - "restrição exclusiva (% s.% S) violada"
* Causa: Uma instrução UPDATE ou INSERT tentou inserir uma chave duplicada. Para Oracle confiável configurado no modo MAC do DBMS, você poderá ver esta mensagem se existir uma entrada duplicada em um nível diferente.
* Ação: remova a restrição exclusiva ou não insira a chave.
Se você preferir ver uma ação de atualização de índice abaixo, é uma demonstração simples no SQL Server. Primeiro, crie uma tabela de duas colunas com um milhão de linhas e um índice não clusterizado na VAL
coluna:
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);
A consulta a seguir pode usar o índice não clusterizado porque o índice é um índice de cobertura para essa consulta. Ele contém todos os dados necessários para executá-lo. Como esperado, nenhum retorno é retornado.
SELECT *
FROM X_TABLE_IX
WHERE VAL = 'A';
Agora vamos iniciar uma transação e atualizar VAL
para quase todas as linhas da tabela:
BEGIN TRANSACTION
UPDATE X_TABLE_IX
SET VAL = 'A'
WHERE ID <> 1;
Aqui está parte do plano de consulta para isso:
Circular em vermelho é a atualização para o índice não clusterizado. Circulada em azul está a atualização do índice clusterizado, que é essencialmente os dados da tabela. Mesmo que a transação não tenha sido confirmada, vemos que os dados e o índice são atualizados em parte da execução da consulta. Observe que você nem sempre verá isso em um plano, dependendo do tamanho dos dados envolvidos, além de outros fatores.
Com a transação ainda não confirmada, vamos revisitar a SELECT
consulta acima.
SELECT *
FROM X_TABLE_IX
WHERE VAL = 'A';
O otimizador de consulta ainda pode usar o índice e, desta vez, estima que 999999 linhas serão retornadas. A execução da consulta retorna o resultado esperado.
Essa foi uma demonstração simples, mas espero que tenha esclarecido um pouco as coisas.
Como um aparte, estou ciente de alguns casos em que se poderia argumentar que um índice não é atualizado imediatamente. Isso é feito por motivos de desempenho e o usuário final não deve poder ver dados inconsistentes. Por exemplo, algumas vezes as exclusões não serão totalmente aplicadas a um índice no SQL Server. Um processo em segundo plano é executado e, eventualmente, limpa os dados. Você pode ler sobre registros fantasmas, se estiver curioso.