Je travaille avec SQL Server et Oracle. Il y a probablement quelques exceptions, mais pour ces plateformes, la réponse générale est que les données et les index seront mis à jour en même temps.
Je pense qu'il serait utile de faire une distinction entre le moment où les index sont mis à jour pour la session propriétaire de la transaction et pour les autres sessions. Par défaut, les autres sessions ne verront pas les index mis à jour tant que la transaction n'est pas validée. Cependant, la session propriétaire de la transaction verra immédiatement les index mis à jour.
Pour une façon d'y penser, pensez à une table avec une clé primaire. Dans SQL Server et Oracle, cela est implémenté en tant qu'index. La plupart du temps, nous voulons qu'il y ait immédiatement une erreur si une action INSERT
est effectuée qui violerait la clé primaire. Pour cela, l'index doit être mis à jour en même temps que les données. Notez que d'autres plateformes, telles que Postgres, autorisent des contraintes différées qui ne sont vérifiées que lorsque la transaction est validée.
Voici une démo rapide d'Oracle montrant un cas courant:
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 deuxième INSERT
instruction renvoie une erreur:
Erreur SQL: ORA-00001: contrainte unique (XXXXXX.SYS_C00384850) violée
00001.
00000 - "contrainte unique (% s.% S) violée"
* Cause: une instruction UPDATE ou INSERT a tenté d'insérer une clé en double. Pour Oracle de confiance configuré en mode MAC SGBD, vous pouvez voir ce message si une entrée en double existe à un niveau différent.
* Action: supprimez la restriction unique ou n'insérez pas la clé.
Si vous préférez voir une action de mise à jour d'index ci-dessous est une simple démonstration dans SQL Server. Créez d'abord une table à deux colonnes avec un million de lignes et un index non cluster sur la VAL
colonne:
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 requête suivante peut utiliser l'index non cluster car l'index est un index de couverture pour cette requête. Il contient toutes les données nécessaires à son exécution. Comme prévu, aucun retour n'est retourné.
SELECT *
FROM X_TABLE_IX
WHERE VAL = 'A';
Maintenant, commençons une transaction et mettons à jour VAL
presque toutes les lignes du tableau:
BEGIN TRANSACTION
UPDATE X_TABLE_IX
SET VAL = 'A'
WHERE ID <> 1;
Voici une partie du plan de requête pour cela:
Entouré de rouge est la mise à jour de l'index non cluster. La mise à jour de l'index cluster, entourée de bleu, est essentiellement les données de la table. Même si la transaction n'a pas été validée, nous voyons que les données et l'index sont mis à jour dans le cadre de l'exécution de la requête. Notez que vous ne verrez pas toujours cela dans un plan en fonction de la taille des données impliquées et éventuellement d'autres facteurs.
La transaction n'étant toujours pas validée, revoyons la SELECT
requête ci-dessus.
SELECT *
FROM X_TABLE_IX
WHERE VAL = 'A';
L'optimiseur de requêtes est toujours en mesure d'utiliser l'index et cette fois, il estime que 999999 lignes seront renvoyées. L'exécution de la requête renvoie le résultat attendu.
C'était une démo simple mais j'espère que cela clarifie un peu les choses.
Soit dit en passant, je suis au courant de quelques cas où l'on pourrait faire valoir qu'un indice n'est pas immédiatement mis à jour. Cette opération est effectuée pour des raisons de performances et l'utilisateur final ne doit pas être en mesure de voir des données incohérentes. Par exemple, il arrive que des suppressions ne soient pas entièrement appliquées à un index dans SQL Server. Un processus d'arrière-plan s'exécute et finit par nettoyer les données. Vous pouvez lire sur les enregistrements fantômes si vous êtes curieux.
D'après mon expérience, un insert de 1 000 000 de lignes nécessitera en fait plus de ressources et prendra plus de temps à compléter que si vous utilisiez des insertions par lots. Cela pourrait être implémenté, par exemple, dans 100 insertions de 10 000 lignes.
Cela réduit les frais généraux des lots insérés et, si un lot échoue, il s'agit d'un retour en arrière plus petit.
Dans tous les cas, pour SQL Server, il existe un utilitaire bcp ou la commande BULK INSERT qui pourrait être utilisée pour effectuer des insertions par lots.
Et, bien sûr, vous pouvez également implémenter votre propre code pour gérer cette approche.
la source