← Toutes les erreurs expliquées

ORA-01555 : Snapshot too old, la lecture qui échoue

Par Omar Sall, DBA Oracle · publié le 26 septembre 2026 · sévérité dans Deynao : Vigilance

Oracle n'a pas pu reconstituer l'image des données telle qu'elle était au début de votre lecture : une version dont il avait besoin, dans les informations d'annulation (l'undo), a été réutilisée entre-temps. La base n'est pas en panne et rien n'est plein au sens habituel. La cause la plus fréquente est une lecture plus longue que la rétention d'undo du moment ; ce n'est pas la seule, et cette page les distingue. Première chose à regarder : la durée de la requête qui a échoué, dans le journal d'alertes, face à la rétention réellement appliquée. Le premier contrôle est dans Vérifier.

Ce que vous voyez

En anglais

ORA-01555: snapshot too old: rollback segment number <n> with name "<nom>" too small

En français

ORA-01555: clichés trop vieux : rollback segment no <n>, nommé "<nom>", trop petit

Le message arrive dans la session qui lisait : un rapport, un export, un traitement de nuit, une requête lancée depuis un outil de requêtage. Le numéro et le nom entre guillemets désignent le segment d'undo dont Oracle avait besoin. Un numéro absent et un nom vide (with name "") sont la forme que la documentation montre pour une lecture de colonnes LOB : ce cas se règle ailleurs que dans le tablespace d'undo (voir plus bas).

Le journal d'alertes de la base porte au même moment une ligne de la forme ORA-01555 caused by SQL statement below (SQL ID: ..., Query Duration=... sec, SCN: ...), suivie du texte de la requête (format documenté sur le site du constructeur). C'est la première pièce à lire : elle nomme la requête qui a échoué et dit combien de temps elle a duré, donc combien de rétention il aurait fallu.

Ce que ça veut dire

Oracle garantit à toute lecture une image cohérente des données au moment où elle commence, même si d'autres sessions modifient les mêmes lignes pendant qu'elle tourne. Pour reconstituer cette image, il relit les anciennes valeurs dans les segments d'undo, où chaque modification laisse de quoi être annulée. Ces segments sont recyclés : une fois la transaction validée, ses informations d'annulation redeviennent réutilisables au bout d'un délai, la rétention. Si votre lecture dure plus longtemps que ce délai et qu'un bloc dont elle a besoin a été réécrit, Oracle ne peut plus fabriquer l'image cohérente. Il abandonne la lecture avec ce code plutôt que de rendre un résultat faux. C'est le sens de la phrase du constructeur : les enregistrements d'annulation dont un lecteur avait besoin ont été écrasés par d'autres écrivains (page d'erreur officielle).

Trois précisions :

Sur le terrain

La séquence typique : un traitement de nuit ou un rapport de fin de mois tourne depuis une ou deux heures, il échoue vers trois heures du matin, et le matin tout va bien. La même requête, relancée en journée, passe. Rien n'est plein, aucune alerte de capacité. C'est ce qui trompe : on cherche un incident, il n'y en a pas. Il y a une lecture plus longue que la rétention du moment, pendant une fenêtre où d'autres traitements écrivaient beaucoup.

Deux autres cas, souvent pris pour le premier :

Un cas plus rare, sur une base calme : après un très gros chargement, des blocs gardent un temps la trace de la transaction qui les a modifiés ; une lecture ultérieure doit consulter l'en-tête du segment d'undo pour savoir si cette transaction était validée, et si cet en-tête a été réutilisé entre-temps, c'est encore ORA-01555, sans aucune écriture concurrente. Le mécanisme, dit nettoyage différé des blocs, est expliqué sur le site du constructeur (AskTom).

Vérifier

Le premier contrôle ci-dessous est celui de Deynao pour ce code, en lecture seule, écrit ici avec l'ordre des lignes rendu explicite. Il demande SELECT sur V_$UNDOSTAT et V_$PARAMETER, accordés directement, sans rôle : c'est exactement ce que fait le script de privilèges de Deynao. Exécuté sur une base 21c ; les colonnes lues sont documentées dès la version 11.2 (référence 11.2), la plus ancienne que Deynao supervise.

-- 1. La tranche de dix minutes la plus récente (si elle date de moins d'une heure) :
--    rétention undo réellement appliquée, plus longue requête, occurrences de l'erreur
SELECT *
FROM (
    SELECT begin_time,
           end_time,
           ROUND(tuned_undoretention / 60, 2) AS tuned_retention_minutes,
           ROUND(maxquerylen / 60, 2)         AS longest_query_minutes,
           maxqueryid,
           ssolderrcnt                        AS ora_01555_count,
           txncount                           AS total_transactions,
           maxconcurrency                     AS max_concurrent_txns
    FROM v$undostat
    WHERE end_time >= SYSDATE - 1/24
    ORDER BY end_time DESC
)
WHERE ROWNUM = 1;

Comment le lire. V$UNDOSTAT garde une ligne par tranche de dix minutes, sur quatre jours (référence de la vue). ora_01555_count compte les occurrences de l'erreur dans la tranche. longest_query_minutes est la durée de la plus longue requête exécutée pendant la tranche, mesurée de l'ouverture du curseur à sa dernière lecture, et maxqueryid son identifiant : ce n'est pas forcément la requête qui a échoué, que seul le journal d'alertes nomme. tuned_retention_minutes est la rétention que la base appliquait réellement à ce moment. Quand une lecture dure plus longtemps que cette rétention, l'erreur devient possible à tout moment : il suffit qu'un bloc dont elle a besoin ait été recyclé. L'inverse n'est pas une garantie. Un résultat vide signifie qu'aucune tranche n'a été enregistrée dans la dernière heure, par exemple juste après un démarrage ; une erreur ORA-00942 signifie que ce compte n'a pas accès à la vue.

Pour retrouver les tranches où l'erreur s'est produite :

-- 2. Les tranches touchées sur les quatre derniers jours, et la plus longue requête de chacune
--    (pas forcément celle qui a échoué : le journal d'alertes la nomme)
SELECT begin_time,
       ssolderrcnt                AS ora_01555_count,
       ROUND(maxquerylen / 60, 2) AS longest_query_minutes,
       maxqueryid
FROM v$undostat
WHERE ssolderrcnt > 0
ORDER BY begin_time DESC;

Pour savoir si la base manquait d'espace d'undo au moment des erreurs, plutôt que de ne regarder que la durée des requêtes :

-- 3. Pression sur l'undo dans les dernières vingt-quatre heures : tranches où la base a repris
--    de l'undo non expiré, a manqué d'espace, ou a produit l'erreur
SELECT begin_time,
       unxpstealcnt  AS reprises_undo_non_expire,
       unxpblkrelcnt AS blocs_non_expires_liberes,
       nospaceerrcnt AS manques_espace,
       ssolderrcnt   AS ora_01555_count
FROM v$undostat
WHERE end_time >= SYSDATE - 1
  AND (unxpstealcnt > 0 OR unxpblkrelcnt > 0 OR nospaceerrcnt > 0 OR ssolderrcnt > 0)
ORDER BY begin_time DESC;

unxpstealcnt compte les tentatives de reprendre de l'undo non expiré à d'autres transactions, unxpblkrelcnt les blocs non expirés effectivement libérés pour d'autres transactions (même référence de la vue). Des valeurs non nulles dans les tranches où l'erreur apparaît disent que la base manquait d'espace d'undo et recyclait ce que des lectures pouvaient encore réclamer : la réponse est alors de l'espace, pas seulement de la rétention. Des compteurs à zéro avec l'erreur présente désignent plutôt une lecture plus longue que la rétention ajustée, ou l'un des cas particuliers décrits plus haut.

Pour l'état du tablespace d'undo à la dernière tranche (blocs de 8 ko : adapter si db_block_size diffère) :

-- 4. État du tablespace d'undo à la dernière tranche : actif, non expiré, expiré
SELECT *
FROM (
    SELECT ROUND(activeblks    * 8192 / 1024 / 1024, 2) AS active_mb,
           ROUND(unexpiredblks * 8192 / 1024 / 1024, 2) AS unexpired_mb,
           ROUND(expiredblks   * 8192 / 1024 / 1024, 2) AS expired_mb,
           end_time
    FROM v$undostat
    ORDER BY end_time DESC
)
WHERE ROWNUM <= 1;

Si l'espace expiré est proche de zéro, tout ce qui reste est actif ou non expiré : sur un tablespace de taille fixe, ou arrivé à sa taille maximale, c'est la taille qui borne la rétention, et monter le paramètre sans donner d'espace ne suffira pas. Les paramètres en vigueur, pour finir :

-- 5. Les paramètres d'undo en vigueur
SELECT name, value
FROM v$parameter
WHERE name IN ('undo_retention', 'undo_tablespace', 'undo_management');

Agir

Dans l'ordre, et chaque étape peut suffire :

  1. Lire la durée de la requête qui a échoué dans le journal d'alertes (Query Duration), et la comparer à TUNED_UNDORETENTION. MAXQUERYLEN ne donne que la plus longue requête de la tranche, pas forcément celle-là. Tant que la lecture dure plus que la rétention disponible, aucune autre action ne tient.
  2. Raccourcir ou déplacer la lecture. Un rapport de deux heures lancé pendant la fenêtre d'écriture la plus dense a plus de chances d'échouer que le même rapport à un autre moment. Optimiser la requête vaut souvent mieux qu'agrandir l'undo.
  3. Donner de la rétention, et l'espace qui va avec. Monter UNDO_RETENTION au-dessus de la durée de la plus longue lecture. Exemple à adapter, jamais à copier tel quel :
ALTER SYSTEM SET undo_retention = 3600 SCOPE = BOTH;

Le paramètre n'est honoré que si l'espace le permet : si le contrôle 3 montre des reprises d'undo non expiré, ou si le tablespace est de taille fixe et déjà occupé par ce que les lectures réclament, agrandir le fichier d'undo, ou le passer en extension automatique avec une taille maximale, avant de compter sur le paramètre. Le bon réglage dépend de la charge, de la configuration et de l'espace réellement disponible, pas d'une règle unique.

  1. Sortir le commit de la boucle si le programme lit et valide la même table ligne à ligne. Aucun réglage de la base ne corrige ce cas.
  2. Pour un LOB, régler la rétention du LOB (RETENTION du stockage SecureFiles, PCTVERSION pour l'ancien format), pas celle de l'undo.

Votre DBA valide, adapte et décide : une rétention plus longue demande plus d'espace d'undo, et un undo saturé fait échouer les écritures (ORA-30036), ce qui est pire qu'un rapport à relancer.

Prévenir

Deux mesures tiennent l'essentiel :

Ce qu'on ne fait pas : activer RETENTION GUARANTEE pour qu'un rapport passe. On échange alors un rapport à relancer contre des écritures qui échouent.

Ce que Deynao en fait

Deynao lit le journal d'alertes de chaque base supervisée et y reconnaît ce code. Il le classe en Vigilance : la base répond et écrit, seule une lecture a échoué. Cette classification est celle du code dans Deynao ; l'impact réel dépend du traitement interrompu, une requête exploratoire ou une clôture de fin de mois, et c'est à l'exploitant de l'apprécier. La fiche affichée explique le mécanisme et donne le contrôle à lancer, avec le privilège qu'il demande. Ce code n'entre pas dans la règle « Alertes Oracle critiques », réservée aux codes critiques ; il apparaît dans le journal expliqué du produit, à sa sévérité.

En amont, le domaine Journalisation lit la rétention d'undo à chaque collecte. Sous 900 secondes, Deynao émet la recommandation « Augmenter la rétention UNDO », avec la cible de 1 800 secondes et le contrôle à lancer ; entre 900 et 1 800 secondes, le score du domaine est simplement pénalisé. Ces seuils sont ceux des règles actuelles de Deynao ; ils ne remplacent pas le dimensionnement de l'undo selon la charge et les lectures propres à chaque base. Deynao lit aussi l'occupation du tablespace d'undo en tenant compte de sa taille maximale d'extension, pas seulement de la taille actuelle du fichier : un fichier de 3 Go occupé à 84 % qui peut grandir jusqu'à 32 Go n'est pas un tablespace plein. Les règles d'alerte du produit et leurs seuils sont publiés : règles d'alerte et temporisations.

Erreurs liées

Sources

Écrit par Omar Sall, DBA Oracle · publié le 26 septembre 2026 · deynao.fr/erreurs-oracle/ora-01555.html

Relu contre Deynao 1.0.3 le 26 septembre 2026 (empreinte de l'entrée de la base de connaissances : dcf67e5546d8). Les recommandations sont expliquées et priorisées, jamais exécutées par Deynao : votre DBA valide, adapte et décide.