Menu

SQLite ATTACH DATABASE : requêter plusieurs fichiers

Comment ATTACH DATABASE permet d'ouvrir plusieurs fichiers SQLite dans une même connexion, de les requêter via des préfixes de schéma et de les détacher proprement.

Cette page contient des éditeurs exécutables — modifiez, exécutez et voyez la sortie instantanément.

Une seule connexion, plusieurs fichiers

Une connexion SQLite n'est pas verrouillée sur un unique fichier. Grâce à ATTACH DATABASE, vous pouvez ouvrir d'autres fichiers .db en plus de celui de départ, puis tous les interroger comme s'il s'agissait de schémas appartenant à la même base. C'est ce que SQLite offre de plus proche de l'idée « plusieurs bases sur un même serveur ».

Voici la forme de base :

Le fichier archive.db est créé s'il n'existe pas, exactement comme la base principale. À partir de maintenant, dans cette session, tout ce qui est préfixé par archive. vit dans ce second fichier. Tout ce qui porte le préfixe main. (ou rien du tout) reste dans la base d'origine.

Votre connexion possède toujours deux schémas implicites : main (le fichier ouvert en premier) et temp (un espace de travail pour les tables temporaires). La commande ATTACH vient en ajouter d'autres.

La syntaxe et le rôle de l'alias

ATTACH DATABASE 'chemin/vers/fichier.db' AS nom_alias;

L'alias, c'est le nom de schéma que vous allez utiliser pour qualifier vos tables. Il reste local à la connexion en cours — une autre connexion qui attache le même fichier peut très bien choisir un alias différent. Prenez quelque chose de court et parlant (archive, analytics, cache), parce que vous allez le retaper souvent.

Quelques points à garder en tête :

  • Le chemin est relatif au répertoire de travail du processus, sauf s'il est absolu.
  • La chaîne ':memory:' attache une nouvelle base en mémoire sous cet alias.
  • L'alias ne peut entrer en conflit ni avec main ni avec temp, et il ne peut pas être réutilisé pour plusieurs attachements.

Faire des jointures entre bases SQLite

C'est généralement la raison principale pour laquelle on fait un ATTACH DATABASE. Dès que deux fichiers cohabitent dans la même connexion, vous pouvez joindre leurs tables dans une seule requête :

Le planificateur de requêtes traite les deux schémas exactement comme les tables de main. Les index des bases attachées sont bien utilisés et EXPLAIN QUERY PLAN fonctionne sans souci entre elles. Pas d'aller-retour réseau non plus : les deux fichiers sont ouverts dans le même processus.

C'est vraiment pratique pour séparer les données chaudes des archives froides, isoler les fichiers par client (multi-tenant), ou sortir les données de référence dans une base de lookup en lecture seule.

Attacher une base SQLite en lecture seule ou en mémoire

Si la deuxième base est censée être consultée mais jamais modifiée — par exemple un jeu de données de référence livré avec l'application — attachez-la en lecture seule via une URI :

La forme URI suppose que la bibliothèque SQLite a été compilée avec SQLITE_OPEN_URI activé (c'est le cas dans la CLI et la plupart des bindings de langage). Dès lors, tout INSERT, UPDATE ou DELETE visant ref.* déclenchera une erreur avant même de toucher au fichier.

Les bases attachées en mémoire sont tout aussi pratiques pour préparer des données temporaires :

scratch disparaît dès que la connexion se ferme. C'est comme temp, sauf que c'est vous qui décides de sa durée de vie.

Les transactions couvrent toutes les bases attachées

Un seul BEGIN/COMMIT englobe les écritures sur main et sur tous les schémas attachés. Soit tout est validé, soit tout est annulé — l'atomicité est garantie d'un fichier à l'autre :

Déplacer des lignes d'une table active vers un fichier d'archive, c'est typiquement le genre d'opération où cette garantie est essentielle. Sans atomicité entre fichiers, un crash en plein milieu vous laisserait avec des doublons ou, pire, des lignes perdues.

Une précision importante : dès que plusieurs bases attachées sont modifiées dans la même transaction, SQLite bascule sur un protocole de commit plus prudent qui nécessite un journal temporaire. C'est plus lent qu'un commit sur un seul fichier, mais ça reste fiable.

Détacher une base avec DETACH DATABASE

Quand vous n'avez plus besoin d'une base attachée, détachez-la :

DETACH DATABASE archive;

Le fichier reste intact sur le disque — DETACH se contente de fermer le handle dans la connexion en cours. Deux restrictions à garder en tête :

  • Impossible de détacher main ou temp.
  • Impossible de détacher une base actuellement engagée dans une transaction ou ayant des statements ouverts.

Et si vous oubliez de détacher, ce n'est pas dramatique : la fermeture de la connexion fait le ménage toute seule.

Limites et erreurs fréquentes

Quelques limites pratiques à connaître :

  • Par défaut, on est plafonné à 10 bases attachées par connexion (en plus de main et temp). Le maximum à la compilation (SQLITE_MAX_ATTACHED) est de 125. Si vous dépassez, vous tomberez sur l'erreur too many attached databases - max 10.
  • Chaque base attachée consomme un cache de pages. Attacher une dizaine de grosses bases n'est pas gratuit — la RAM grimpe vite.
  • ATTACH ne peut pas s'exécuter à l'intérieur d'une transaction. Lancez-le avant BEGIN, ou après COMMIT.

Voici quelques erreurs que vous risquez de croiser :

-- Le fichier n'existe pas et le répertoire n'est pas accessible en écriture :
Error: unable to open database: 'missing/path.db'

-- Vous avez tenté d'écrire sur une pièce jointe en lecture seule :
Error: attempt to write a readonly database

-- Vous avez utilisé le même alias deux fois :
Error: database archive is already in use

La plupart de ces points coulent de source dès qu'on les lit. Le « already in use » piège souvent les débutants : ATTACH ne remplace pas un alias existant, il faut d'abord faire un DETACH.

Un cas concret : séparer données chaudes et froides

Mettons tout ça en pratique avec un petit workflow d'archivage qui déplace les commandes de plus d'un an hors de la base principale :

Les anciennes lignes basculent vers archive.orders, les récentes restent dans main. Les rapports qui ont besoin de l'historique font une jointure entre les deux ; les requêtes du quotidien sur main.orders restent rapides puisque la table est plus petite. Une seule connexion, deux fichiers, une seule transaction.

La suite : les requêtes préparées

ATTACH permet à une connexion d'accéder à plus de données. Les prochains sujets portent sur la manière dont les applications dialoguent avec SQLite de façon sûre et performante — à commencer par les requêtes préparées (prepared statements), socle du binding de paramètres et des requêtes à l'épreuve des injections.

Questions fréquentes

À quoi sert ATTACH DATABASE dans SQLite ?

ATTACH DATABASE 'fichier.db' AS alias ouvre un second fichier SQLite à l'intérieur de la connexion en cours et lui associe un nom de schéma. Ensuite, vous accédez à ses tables via alias.nom_table et vous pouvez les joindre avec celles de votre base principale dans une seule et même requête.

Combien de bases SQLite peut-on attacher en même temps ?

Par défaut, SQLite autorise jusqu'à 10 bases attachées par connexion, en plus des schémas main et temp. Le plafond absolu est de 125, configurable à la compilation via SQLITE_MAX_ATTACHED. Si vous dépassez, vous obtenez l'erreur too many attached databases.

Peut-on requêter plusieurs bases attachées dans une seule instruction ?

Oui. Une fois la base attachée, il suffit de préfixer chaque table par son nom de schéma : SELECT * FROM main.users JOIN archive.orders ON .... Les jointures, sous-requêtes et INSERT ... SELECT fonctionnent entre schémas. Les transactions s'étendent aussi à toutes les bases attachées : un COMMIT est atomique sur l'ensemble des fichiers.

Comment détacher une base SQLite ?

Exécutez DETACH DATABASE alias. Le fichier reste intact sur le disque — DETACH se contente de fermer le handle dans la connexion en cours. Impossible en revanche de détacher main ou temp, ni une base au beau milieu d'une transaction.

Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER