1. Introduction2. Neuf types de fichiers temporaires2.1. Journaux de retour en arrière2.2. Fichiers journaux en tête d'écriture (WAL)2.3. Fichiers à mémoire partagée2.4. Fichiers de super-journal2.5. Fichiers de journal des relevés2.6. Bases de données TEMP2.7. Matérialisations de vues et de sous-requêtes2.8. Indices transitoires2.9. Base de données transitoire utilisée par VACUUM3. Le paramètre de compilation et le pragma SQLITE_TEMP_STORE4. Autres optimisations des fichiers temporaires5. Emplacements de stockage des fichiers temporaires

L'une des caractéristiques distinctives de SQLite est qu'une base de données est constituée d'un seul fichier disque. Cela simplifie l'utilisation de SQLite puisque le déplacement ou la sauvegarde d'une base de données est aussi simple que la copie d'un seul fichier. Cela rend également SQLite approprié pour une utilisation en tant que format de fichier d'application. Mais alors qu'une base de données complète est tenue dans un seul fichier disque, SQLite fait usage de nombreux fichiers temporaires au cours du traitement d'une base de données.

Cet article décrit les différents fichiers temporaires que SQLite crée et utilise. Il décrit quand les fichiers sont créés, quand ils sont supprimés, à quoi ils servent, pourquoi ils sont importants et comment les éviter sur les systèmes où la création de fichiers temporaires est coûteuse.

La manière dont SQLite utilise les fichiers temporaires n'est pas considérée comme faisant partie du contrat que SQLite passe avec les applications. Les informations contenues dans ce document sont une description correcte du fonctionnement de SQLite au moment où ce document a été écrit ou mis à jour pour la dernière fois. Mais il n'y a aucune garantie que les futures versions de SQLite utiliseront les fichiers temporaires de la même manière. De nouveaux types de fichiers temporaires pourraient être employés et certaines des utilisations actuelles des fichiers temporaires pourraient être abandonnées dans les futures versions de SQLite.

SQLite utilise actuellement neuf types distincts de fichiers temporaires :

  1. Journaux de retour en arrière
  2. Super-journaux
  3. Fichiers de journal en tête d'écriture (WAL)
  4. Fichiers à mémoire partagée
  5. Journaux d'états
  6. Bases de données TEMP
  7. Matérialisations de vues et de sous-requêtes
  8. Indices transitoires
  9. Bases de données transitoires utilisées par VACUUM

Des informations supplémentaires sur chacun de ces types de fichiers temporaires se trouvent dans la suite.

2.1. Journaux de retour en arrière

Un journal de rollback est un fichier temporaire utilisé pour implémenter les capacités de commit et rollback atomiques dans SQLite. (Pour une discussion détaillée de la façon dont cela fonctionne, voir le document séparé intitulé Atomic Commit In SQLite). Le journal de rollback est toujours situé dans le même répertoire que le fichier de base de données et a le même nom que le fichier de base de données sauf avec les 8 caractères "-journal" ajoutés. Le journal de retour en arrière est généralement créé lorsqu'une transaction est lancée pour la première fois et est généralement supprimé lorsqu'une transaction est validée ou annulée. Le fichier journal de rollback est essentiel pour mettre en œuvre les capacités de commit et rollback atomiques de SQLite. Sans journal de rollback, SQLite serait incapable de rollbacker une transaction incomplète, et si un crash ou une perte de puissance se produisait au milieu d'une transaction, la base de données entière serait probablement corrompue sans journal de rollback.

Le journal de rollback est habituellement créé et détruit respectivement au début et à la fin d'une transaction. Mais il existe des exceptions à cette règle.

Si un crash ou une perte de puissance se produit au milieu d'une transaction, alors le fichier journal de rollback est laissé sur le disque. La prochaine fois qu'une autre application tente d'ouvrir le fichier de la base de données, elle remarque la présence du journal de rollback abandonné (nous l'appelons un "journal chaud" dans cette circonstance) et utilise les informations du journal pour restaurer la base de données dans son état antérieur au début de la transaction incomplète. C'est ainsi que SQLite implémente le commit atomique.

Si une application met SQLite en mode de verrouillage exclusif en utilisant le pragma :

PRAGMA locking_mode=EXCLUSIVE;

SQLite crée un nouveau journal de rollback au début de la première transaction dans une session en mode de verrouillage exclusif. Mais à la conclusion de la transaction, il ne supprime pas le journal de rollback. Le journal de rollback peut être tronqué, ou son en-tête peut être mis à zéro (selon la version de SQLite que vous utilisez) mais le journal de rollback n'est pas supprimé. Le journal de retour en arrière n'est pas supprimé tant que le mode d'accès exclusif n'est pas quitté.

La création et la suppression du journal de rollback sont également modifiées par le pragma journal_mode. Le mode de journalisation par défaut est DELETE, ce qui correspond au comportement par défaut de suppression du fichier de journal de rollback à la fin de chaque transaction, comme décrit ci-dessus. Le mode de journalisation PERSIST renonce à la suppression du fichier de journal et écrase à la place l'en-tête du journal de retour en arrière avec des zéros, ce qui empêche les autres processus de revenir en arrière dans le journal et a donc le même effet que la suppression du fichier de journal, mais sans la dépense de supprimer réellement le fichier du disque. En d'autres termes, le mode journal PERSIST présente le même comportement que le mode de verrouillage EXCLUSIVE. Le mode journal OFF permet à SQLite d'omettre complètement le journal de retour en arrière. En d'autres termes, aucun journal de retour en arrière n'est jamais écrit si le mode journal est réglé sur OFF. Le mode journal OFF désactive les capacités atomiques de commit et de rollback de SQLite. La commande ROLLBACK n'est pas disponible lorsque le mode journal OFF est activé. Et si un crash ou une perte de puissance se produit au milieu d'une transaction qui utilise le mode journal OFF, aucune récupération n'est possible et le fichier de la base de données sera probablement corrompu. Le mode journal MEMORY fait en sorte que le journal de retour en arrière soit stocké en mémoire plutôt que sur le disque. La commande ROLLBACK fonctionne toujours lorsque le mode journal est MEMORY, mais comme aucun fichier n'existe sur les disques pour la récupération, un crash ou une perte de puissance au milieu d'une transaction qui utilise le mode journal MEMORY aura probablement pour résultat une base de données corrompue.

2.2. Fichiers de journal d'écriture (WAL)

Un journal en tête d'écriture ou fichier WAL est utilisé à la place d'un journal de retour en arrière lorsque SQLite fonctionne en mode WAL. Comme avec le journal de rollback, le but du fichier WAL est d'implémenter le commit et le rollback atomiques. Le fichier WAL est toujours situé dans le même répertoire que le fichier de base de données et a le même nom que le fichier de base de données, mais avec les 4 caractères "-wal" ajoutés. Le fichier WAL est créé lorsque la première connexion à la base de données est ouverte et est normalement supprimé lorsque la dernière connexion à la base de données se ferme. Cependant, si la dernière connexion ne se ferme pas proprement, le fichier WAL restera dans le système de fichiers et sera automatiquement nettoyé à la prochaine ouverture de la base de données.

2.3. Fichiers à mémoire partagée

Lors du fonctionnement en mode WAL, toutes les connexions de base de données SQLite associées au même fichier de base de données doivent partager une certaine mémoire qui est utilisée comme index pour le fichier WAL. Dans la plupart des implémentations, cette mémoire partagée est mise en œuvre en appelant mmap() sur un fichier créé dans ce seul but : le fichier de mémoire partagée. Le fichier de mémoire partagée, s'il existe, est situé dans le même répertoire que le fichier de base de données et a le même nom que le fichier de base de données, à l'exception des 4 caractères "-shm" ajoutés. Les fichiers de mémoire partagée n'existent que lors de l'exécution en mode WAL.

Le fichier de mémoire partagée ne contient aucun contenu persistant. Le seul but du fichier de mémoire partagée est de fournir un bloc de mémoire partagée à utiliser par plusieurs processus accédant tous à la même base de données en mode WAL. Si le VFS est capable de fournir une méthode alternative pour accéder à la mémoire partagée, cette méthode alternative peut être utilisée plutôt que le fichier de mémoire partagée. Par exemple, si PRAGMA locking_mode est défini sur EXCLUSIVE (ce qui signifie qu'un seul processus est capable d'accéder au fichier de base de données), alors la mémoire partagée sera allouée à partir du tas plutôt qu'à partir du fichier de mémoire partagée, et le fichier de mémoire partagée ne sera jamais créé.

Le fichier de mémoire partagée a la même durée de vie que son fichier WAL associé. Le fichier à mémoire partagée est créé lorsque le fichier WAL est créé et est supprimé lorsque le fichier WAL est supprimé. Pendant la récupération du fichier WAL, le fichier de mémoire partagée est recréé à partir de zéro en fonction du contenu du fichier WAL en cours de récupération.

2.4. Fichiers super-journaux

Le fichier super-journal est utilisé dans le cadre du processus de livraison atomique lorsqu'une seule transaction apporte des modifications à plusieurs bases de données qui ont été ajoutées à une seule connexion de base de données à l'aide de l'instruction ATTACH. Le fichier super-journal est toujours situé dans le même répertoire que le fichier de base de données principal (le fichier de base de données principal est la base de données identifiée dans l'appel original sqlite3_open(), sqlite3_open16() ou sqlite3_open_v2() qui a créé la connexion à la base de données) avec un suffixe aléatoire. Le fichier super-journal contient les noms de toutes les bases de données auxiliaires attachées qui ont été modifiées pendant la transaction. La transaction multi-bases de données est validée lorsque le fichier super-journal est supprimé. Pour plus de détails, consultez la documentation intitulée Atomic Commit In SQLite.

Sans le super-journal, le commit d'une transaction multi-bases de données serait atomique pour chaque base de données individuellement, mais il ne serait pas atomique pour toutes les bases de données. En d'autres termes, si la validation était interrompue en plein milieu par un crash ou une coupure de courant, les modifications apportées à l'une des bases de données pourraient se terminer alors que les modifications apportées à une autre base de données pourraient être annulées. Le super-journal fait en sorte que tous les changements dans toutes les bases de données soient soit rollback soit commit ensemble.

Le fichier super-journal est uniquement créé pour les opérations COMMIT qui impliquent plusieurs fichiers de base de données où au moins deux des bases de données répondent à toutes les exigences suivantes :

  1. La base de données est modifiée par la transaction
  2. Le paramètre synchrone PRAGMA n'est pas désactivé.
  3. Le paramètre PRAGMA journal_mode n'est pas OFF, MEMORY, ou WAL

Cela signifie que les transactions SQLite ne sont pas atomiques sur plusieurs fichiers de base de données lors d'une perte de courant lorsque les fichiers de base de données ont le synchrone désactivé ou lorsqu'ils utilisent des modes de journal de OFF, MEMORY ou WAL. Pour le mode synchrone OFF et pour les modes journal OFF et MEMORY, la base de données sera généralement corrompue si un commit de transaction est interrompu par une perte de puissance. Pour le mode WAL, les fichiers individuels de la base de données sont mis à jour de manière atomique à travers une perte de courant, mais dans le cas de transactions multi-fichiers, certains fichiers pourraient revenir en arrière tandis que d'autres avancent après le rétablissement du courant.

2.5. Fichiers de journal des relevés

Un fichier journal d'instruction est utilisé pour annuler les résultats partiels d'une seule instruction dans une transaction plus importante. Par exemple, supposons qu'une instruction UPDATE tente de modifier 100 lignes dans la base de données. Mais après avoir modifié les 50 premières lignes, l'UPDATE rencontre une violation de contrainte qui devrait bloquer l'ensemble de l'instruction. Le journal des instructions est utilisé pour annuler les modifications des 50 premières lignes afin que la base de données soit restaurée à l'état dans lequel elle se trouvait au début de l'instruction.

Un journal d'instruction n'est créé que pour une instruction UPDATE ou INSERT qui pourrait modifier plusieurs lignes d'une base de données et qui pourrait heurter une contrainte ou une exception RAISE dans un déclencheur et donc avoir besoin d'annuler des résultats partiels. Si l'instruction UPDATE ou INSERT n'est pas contenue dans BEGIN...COMMIT et s'il n'y a pas d'autres instructions actives sur la même connexion de base de données, aucun journal d'instructions n'est créé puisque le journal de retour en arrière ordinaire peut être utilisé à la place. Le journal des déclarations est également omis si un autre algorithme de résolution des conflits est utilisé. Par exemple :

UPDATEOR FAIL UPDATEORIGNOREUPDATEORREPLACEUPDATEORROLLBACKINSERTOR FAIL INSERTORIGNOREINSERTORREPLACEINSERTORROLLBACKREPLACEINTO

Le journal des déclarations reçoit un nom aléatoire, pas nécessairement dans le même répertoire que la base de données principale, et est automatiquement supprimé à la fin de la transaction. La taille du journal des déclarations est proportionnelle à la taille de la modification mise en œuvre par la déclaration UPDATE ou INSERT qui a provoqué la création du journal des déclarations.

2.6. Bases de données TEMP

Les tables créées à l'aide de la syntaxe "CREATE TEMP TABLE" ne sont visibles que pour la connexion à la base de données dans laquelle l'instruction "CREATE TEMP TABLE" est initialement évaluée. Ces tables TEMP, ainsi que tous les index, déclencheurs et vues associés, sont collectivement stockés dans un fichier de base de données temporaire séparé qui est créé dès que la première instruction "CREATE TEMP TABLE" est vue. Ce fichier de base de données temporaire séparé a également un journal de retour en arrière associé. Le fichier de base de données temporaire utilisé pour stocker les tables TEMP est supprimé automatiquement lorsque la connexion à la base de données est fermée à l'aide de sqlite3_close().

Le fichier de base de données TEMP est très similaire aux fichiers de base de données auxiliaires ajoutés à l'aide de l'instruction ATTACH, mais avec quelques propriétés particulières. La base de données TEMP est toujours automatiquement supprimée lorsque la connexion à la base de données est fermée. La base de données TEMP utilise toujours les paramètres PRAGMA synchrone=OFF et journal_mode=PERSIST. Et, la base de données TEMP ne peut pas être utilisée avec DETACH et un autre processus ne peut pas ATTACHER la base de données TEMP.

Les fichiers temporaires associés à la base de données TEMP et à son journal de rollback ne sont créés que si l'application fait usage de l'instruction "CREATE TEMP TABLE".

2.7. Matérialisations des vues et des sous-requêtes

Les requêtes qui contiennent des sous-requêtes doivent parfois évaluer les sous-requêtes séparément et stocker les résultats dans une table temporaire, puis utiliser le contenu de la table temporaire pour évaluer la requête externe. Nous appelons cela "matérialiser" la sous-requête. L'optimiseur de requêtes de SQLite tente d'éviter la matérialisation, mais parfois il n'est pas facile de l'éviter. Les tables temporaires créées par la matérialisation sont chacune stockées dans leur propre fichier temporaire séparé, qui est automatiquement supprimé à la fin de la requête. La taille de ces tables temporaires dépend de la quantité de données dans la matérialisation de la sous-requête, bien sûr.

Une sous-requête à droite de l'opérateur IN doit souvent être matérialisée. Par exemple :

SELECT*FROM ex1 WHERE ex1a IN(SELECT b FROM ex2);

Dans la requête ci-dessus, la sous-requête "SELECT b FROM ex2" est évaluée et ses résultats sont stockés dans une table temporaire (en fait un index temporaire) qui permet de déterminer si une valeur ex2.b existe ou non en utilisant une simple recherche binaire. Une fois cette table construite, la requête externe est exécutée et pour chaque ligne de résultats potentiels, une vérification est effectuée pour voir si ex1.a est contenu dans la table temporaire. La ligne est éditée uniquement si la vérification est vraie.

Pour éviter de créer la table temporaire, la requête pourrait être réécrite comme suit :

SELECT*FROM ex1 WHEREEXISTS(SELECT1FROM ex2 WHERE ex2b=ex1a);

Les versions récentes de SQLite (version 3.5.4 2007-12-14) et ultérieures) feront cette réécriture automatiquement si un index existe sur la colonne ex2.b.

Si le côté droit d'un opérateur IN peut être une liste de valeurs comme dans ce qui suit :

SELECT*FROM ex1 WHERE a IN(1,2,3);

Les valeurs de liste du côté droit de IN sont traitées comme une sous-requête qui doit être matérialisée. En d'autres termes, l'instruction précédente agit comme si elle était :

SELECT*FROM ex1 WHERE a IN(SELECT1UNIONALLSELECT2UNIONALLSELECT3);

Un index temporaire est toujours utilisé pour contenir les valeurs du côté droit d'un opérateur IN lorsque ce côté droit est une liste de valeurs.

Les sous-requêtes peuvent également devoir être matérialisées lorsqu'elles apparaissent dans la clause FROM d'une instruction SELECT. Par exemple :

SELECT*FROM ex1 JOIN(SELECT b FROM ex2)AS t ON tb=ex1a;

Selon la requête, SQLite pourrait devoir matérialiser la sous-requête "(SELECT b FROM ex2)" dans une table temporaire, puis effectuer la jointure entre ex1 et la table temporaire. L'optimiseur de requêtes essaie d'éviter cela en "aplatissant" la requête. Dans l'exemple précédent, la requête peut être aplatie, et SQLite transformera automatiquement la requête en

SELECT ex1*, ex2b FROM ex1 JOIN ex2 ON ex2b=ex1a;

Des requêtes plus complexes peuvent ou non être en mesure d'employer l'aplatissement de requête pour éviter la table temporaire. La possibilité ou non d'aplatir la requête dépend de facteurs tels que le fait que la sous-requête ou la requête externe contiennent ou non des fonctions d'agrégation, des clauses ORDER BY ou GROUP BY, des clauses LIMIT, etc. Les règles pour savoir quand une requête peut et ne peut pas être aplatie sont très complexes et dépassent le cadre de ce document.

2.8. Indices transitoires

SQLite peut faire usage d'indices transitoires pour mettre en œuvre des fonctionnalités du langage SQL telles que :

  • Une clause ORDER BY ou GROUP BY
  • Le mot clé DISTINCT dans une requête agrégée.
  • Les instructions SELECT composées jointes par UNION, EXCEPT ou INTERSECT.

Chaque index transitoire est stocké dans son propre fichier temporaire. Le fichier temporaire d'un index transitoire est automatiquement supprimé à la fin de l'instruction qui l'utilise.

SQLite s'efforce d'implémenter les clauses ORDER BY en utilisant un index préexistant. Si un index approprié existe déjà, SQLite va parcourir l'index, plutôt que la table sous-jacente, pour extraire l'information demandée, et ainsi faire sortir les lignes dans l'ordre souhaité. Mais si SQLite ne trouve pas d'index approprié, il évalue la requête et stocke chaque ligne dans un index transitoire dont les données sont celles de la ligne et dont la clé est les termes ORDER BY. Après l'évaluation de la requête, SQLite revient en arrière et parcourt l'index transitoire du début à la fin afin de sortir les lignes dans l'ordre souhaité.

SQLite met en œuvre GROUP BY en ordonnant les lignes de sortie dans l'ordre suggéré par les termes GROUP BY. Chaque ligne de sortie est comparée à la précédente pour voir si elle commence un nouveau "groupe". Le classement par les termes GROUP BY est effectué exactement de la même manière que le classement par les termes ORDER BY. Un index préexistant est utilisé si possible, mais si aucun index approprié n'est disponible, un index transitoire est créé.

Le mot clé DISTINCT sur une requête agrégée est mis en œuvre en créant un index transitoire dans un fichier temporaire et en stockant chaque ligne de résultat dans cet index. Lorsque de nouvelles lignes de résultat sont calculées, une vérification est faite pour voir si elles existent déjà dans l'index transitoire et si c'est le cas, la nouvelle ligne de résultat est écartée.

L'opérateur UNION pour les requêtes composées est implémenté en créant un index transitoire dans un fichier temporaire et en stockant les résultats de la sous-requête de gauche et de droite dans l'index transitoire, en écartant les doublons. Après que les deux sous-requêtes ont été évaluées, l'index transitoire est parcouru du début à la fin pour générer la sortie finale.

L'opérateur EXCEPT pour les requêtes composées est mis en œuvre en créant un index transitoire dans un fichier temporaire, en stockant les résultats de la sous-requête gauche dans cet index transitoire, puis en retirant le résultat de la sous-requête droite de l'index transitoire, et enfin en parcourant l'index du début à la fin pour obtenir la sortie finale.

L'opérateur INTERSECT pour les requêtes composées est implémenté en créant deux index transitoires distincts, chacun dans un fichier temporaire séparé. Les sous-requêtes de gauche et de droite sont évaluées chacune dans un index transitoire séparé. Ensuite, les deux index sont parcourus ensemble et les entrées qui apparaissent dans les deux index sont sorties.

Notez que l'opérateur UNION ALL pour les requêtes composées n'utilise pas d'indices transitoires par lui-même (même si, bien sûr, les sous-requêtes de droite et de gauche de l'UNION ALL pourraient utiliser des indices transitoires selon la façon dont elles sont composées).

2.9. Base de données transitoire utilisée par VACUUM

La commande VACUUM fonctionne en créant un fichier temporaire, puis en reconstruisant l'ensemble de la base de données dans ce fichier temporaire. Ensuite, le contenu du fichier temporaire est recopié dans le fichier de base de données original et le fichier temporaire est supprimé.

Le fichier temporaire créé par la commande VACUUM n'existe que pour la durée de la commande elle-même. La taille du fichier temporaire ne sera pas plus grande que celle de la base de données originale.

Les fichiers temporaires associés au contrôle des transactions, à savoir le journal de retour en arrière, le super-journal, les fichiers journaux d'écriture (WAL) et les fichiers de mémoire partagée, sont toujours écrits sur le disque. Mais les autres types de fichiers temporaires peuvent être stockés en mémoire uniquement et ne jamais être écrits sur le disque. Le fait que les fichiers temporaires autres que les journaux de rollback, de super et d'instructions soient écrits sur le disque ou stockés uniquement en mémoire dépend du paramètre de compilation SQLITE_TEMP_STORE, du pragma temp_store et de la taille du fichier temporaire.

Le paramètre de compilation SQLITE_TEMP_STORE est un #define dont la valeur est un nombre entier compris entre 0 et 3, inclus. La signification du paramètre de compilation SQLITE_TEMP_STORE est la suivante :

  1. Les fichiers temporaires sont toujours stockés sur le disque, quel que soit le paramètre du pragma temp_store.
  2. Les fichiers temporaires sont stockés sur le disque par défaut, mais cela peut être remplacé par le pragma temp_store.
  3. Les fichiers temporaires sont stockés en mémoire par défaut mais cela peut être remplacé par le pragma temp_store.
  4. Les fichiers temporaires sont toujours stockés en mémoire, quel que soit le paramètre du pragma temp_store.

La valeur par défaut du paramètre de compilation SQLITE_TEMP_STORE est 1, ce qui signifie stocker les fichiers temporaires sur le disque mais fournir la possibilité de remplacer le comportement en utilisant le pragma temp_store.

Le pragma temp_store a une valeur entière qui influence également la décision de l'endroit où stocker les fichiers temporaires. Les valeurs du pragma temp_store ont les significations suivantes :

  1. Utiliser le stockage sur disque ou en mémoire pour les fichiers temporaires, comme déterminé par le paramètre de compilation SQLITE_TEMP_STORE.
  2. Si le paramètre de compilation SQLITE_TEMP_STORE spécifie le stockage en mémoire pour les fichiers temporaires, alors annulez cette décision et utilisez plutôt le stockage sur disque. Sinon, suivez la recommandation du paramètre de compilation SQLITE_TEMP_STORE.
  3. Si le paramètre de compilation SQLITE_TEMP_STORE spécifie le stockage sur disque pour les fichiers temporaires, alors passez outre cette décision et utilisez plutôt le stockage en mémoire. Sinon, suivez la recommandation du paramètre de compilation SQLITE_TEMP_STORE.

Le paramètre par défaut du pragma temp_store est 0, ce qui signifie suivre la recommandation du paramètre de compilation SQLITE_TEMP_STORE.

Pour réitérer, le paramètre de compilation SQLITE_TEMP_STORE et le pragma temp_store n'influencent que les fichiers temporaires autres que le journal de rollback et le super-journal. Le journal de rollback et le super-journal sont toujours écrits sur le disque, quels que soient les paramètres du paramètre de compilation SQLITE_TEMP_STORE et du pragme temp_store.

SQLite utilise un cache de pages de la base de données récemment lues et écrites. Ce cache de pages est utilisé non seulement pour le fichier principal de la base de données, mais aussi pour les index et les tables transitoires stockés dans des fichiers temporaires. Si SQLite doit utiliser un index ou une table temporaire et que le paramètre de compilation SQLITE_TEMP_STORE et le pragma temp_store sont définis pour stocker les tables et l'index temporaires sur le disque, les informations sont toujours initialement stockées en mémoire dans le cache de page. Le fichier temporaire n'est pas ouvert et les informations ne sont pas véritablement écrites sur le disque avant que le cache de page ne soit plein.

Cela signifie que pour de nombreux cas courants où les tables et les index temporaires sont petits (suffisamment petits pour tenir dans le cache de page), aucun fichier temporaire n'est créé et aucune E/S disque ne se produit. Ce n'est que lorsque les données temporaires deviennent trop grandes pour tenir dans la RAM que les informations se déversent sur le disque.

Chaque table et index temporaire reçoit son propre cache de pages qui peut stocker un nombre maximum de pages de base de données déterminé par le paramètre de compilation SQLITE_DEFAULT_TEMP_CACHE_SIZE. (La valeur par défaut est de 500 pages.) Le nombre maximal de pages de base de données dans le cache de pages est le même pour chaque table et index temporaire. La valeur ne peut pas être modifiée lors de l'exécution ou sur une base par table ou par index. Chaque fichier temporaire obtient son propre cache de pages privé avec sa propre limite de pages SQLITE_DEFAULT_TEMP_CACHE_SIZE.

Le répertoire ou le dossier dans lequel les fichiers temporaires sont créés est déterminé par le VFS spécifique au système d'exploitation.

Sur les systèmes de type unix, les répertoires sont recherchés dans l'ordre suivant :

  1. Le répertoire défini par PRAGMA temp_store_directory ou par la variable globale sqlite3_temp_directory.
  2. La variable d'environnement SQLITE_TMPDIR
  3. La variable d'environnement TMPDIR
  4. /var/tmp
  5. /usr/tmp
  6. /tmp
  7. Le répertoire de travail actuel (".")

Le premier des éléments ci-dessus qui est trouvé pour exister et avoir les bits d'écriture et d'exécution définis est utilisé. Le repli final "." est important pour certaines applications qui utilisent SQLite à l'intérieur de jails chroot qui n'ont pas les emplacements de fichiers temporaires standard disponibles.

Sur les systèmes Windows, les dossiers sont recherchés dans l'ordre suivant :

  1. Le dossier défini par PRAGMA temp_store_directory ou par la variable globale sqlite3_temp_directory.
  2. Le dossier renvoyé par l'interface système GetTempPath().

SQLite lui-même ne fait pas attention aux variables d'environnement dans ce cas, mais on peut supposer que l'appel système GetTempPath() le fait. L'algorithme de recherche est différent pour les constructions CYGWIN. Consultez le code source pour plus de détails.