Lavoro con SQL Server e Oracle. Probabilmente ci sono alcune eccezioni, ma per quelle piattaforme la risposta generale è che i dati e gli indici verranno aggiornati contemporaneamente.
Penso che sarebbe utile fare una distinzione tra quando gli indici vengono aggiornati per la sessione proprietaria della transazione e per altre sessioni. Per impostazione predefinita, le altre sessioni non vedranno gli indici aggiornati finché non viene eseguito il commit della transazione. Tuttavia, la sessione proprietaria della transazione vedrà immediatamente gli indici aggiornati.
Per un modo di pensarci, considera a un tavolo con una chiave primaria. In SQL Server e Oracle questo è implementato come indice. La maggior parte delle volte desideriamo INSERT
che si verifichi immediatamente un errore in caso di violazione della chiave primaria. Perché ciò accada, l'indice deve essere aggiornato contemporaneamente ai dati. Si noti che altre piattaforme, come Postgres, consentono vincoli differiti che vengono verificati solo al momento del commit della transazione.
Ecco una breve demo di Oracle che mostra un caso comune:
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 seconda INSERT
istruzione genera un errore:
Errore SQL: ORA-00001: vincolo univoco (XXXXXX.SYS_C00384850) violato
00001.
00000 - "Violazione del vincolo univoco (% s.% S)"
* Causa: un'istruzione UPDATE o INSERT ha tentato di inserire una chiave duplicata. Per Trusted Oracle configurato in modalità DBMS MAC, è possibile che venga visualizzato questo messaggio se esiste una voce duplicata a un livello diverso.
* Azione: rimuovere la limitazione univoca o non inserire la chiave.
Se si preferisce vedere un'azione di aggiornamento dell'indice di seguito è una semplice demo in SQL Server. Innanzitutto crea una tabella a due colonne con un milione di righe e un indice non cluster sulla VAL
colonna:
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 query seguente può utilizzare l'indice non cluster poiché l'indice è un indice di copertura per quella query. Contiene tutti i dati necessari per eseguirlo. Come previsto, non vengono restituiti resi.
SELECT *
FROM X_TABLE_IX
WHERE VAL = 'A';
Ora iniziamo una transazione e aggiorniamo VAL
per quasi tutte le righe della tabella:
BEGIN TRANSACTION
UPDATE X_TABLE_IX
SET VAL = 'A'
WHERE ID <> 1;
Ecco parte del piano di query per questo:
Cerchiato in rosso è l'aggiornamento all'indice non cluster. Cerchiato in blu è l'aggiornamento all'indice cluster, che è essenzialmente i dati della tabella. Anche se la transazione non è stata impegnata, vediamo che i dati e l'indice vengono aggiornati durante l'esecuzione della query. Nota che non lo vedrai sempre in un piano a seconda della dimensione dei dati coinvolti e probabilmente di altri fattori.
Con la transazione ancora non impegnata, rivisitiamo la SELECT
query dall'alto.
SELECT *
FROM X_TABLE_IX
WHERE VAL = 'A';
Query Optimizer è ancora in grado di utilizzare l'indice e questa volta stima che verranno restituite 999999 righe. L'esecuzione della query restituisce il risultato previsto.
Era una semplice demo ma, si spera, ha chiarito un po 'le cose.
Per inciso, sono a conoscenza di alcuni casi in cui si potrebbe sostenere che un indice non viene immediatamente aggiornato. Questo viene fatto per motivi di prestazioni e l'utente finale non dovrebbe essere in grado di vedere dati incoerenti. Ad esempio, a volte le eliminazioni non verranno applicate completamente a un indice in SQL Server. Viene eseguito un processo in background e infine pulisce i dati. Puoi leggere informazioni sui dischi fantasma se sei curioso.