2014-06-17 5 views
2

J'utilise une base de données SQLite dans mon application pour stocker des données de mesure.SQLite: Mauvaises performances avec ON DELETE CASCADE

Il est organisé en groupes dans les projets. Les tables sont interconnectées avec des clés étrangères, qui utilisent ON DELETE CASCADE pour gérer les liens. La base de données ressemble à ceci:

  • Tableau Projets
  • Tableau Groupes (clé étrangère: project_id)
  • Tableau des fichiers (clé étrangère: group_id)
  • Tableau Datapoints (clé étrangère: file_id)

Toutes les colonnes de référence de clés étrangères déclarées comme

project_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT.

Les clés étrangères sont déclarées comme celui-ci

FOREIGN KEY(project_id) REFERENCES Projects(project_id) ON DELETE CASCADE

Maintenant, j'ai 1 projet, 1 groupe dans le projet, 800 fichiers dans ce groupe et environ 60 points de données par fichier.

La suppression du groupe DELETE FROM Groups WHERE project_id=1 fonctionne bien mais cela prend environ 21 secondes, ce qui est beaucoup trop long pour mes besoins.

J'ai enveloppé la suppression dans une transaction. Je suis un débutant extrême en SQL et SQLite. Cette durée est-elle normale ou existe-t-il un moyen de l'accélérer? J'ai besoin de supprimer le groupe pour remplir les valeurs mises à jour. Dans mon application, je veux seulement garder un projet en mémoire, donc il suffit de supprimer toute la base de données et de la remplir à partir de zéro (bien que beaucoup plus rapide, ~ 1 sek) n'est pas vraiment une option.

Les tables sont créées comme ceci:

'Create projects table 
cmd.CommandText = "CREATE TABLE IF NOT EXISTS Projects (ProjectID INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " & _ 
     "name TEXT NOT NULL, comment TEXT, date DATETIME2, diameter FLOAT(53), thickness FLOAT(53));" 

'Create Groups table 
cmd.CommandText &= vbNewline & "CREATE TABLE IF NOT EXISTS Groups (GroupID INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, project_id INTEGER NOT NULL, " & _ 
     "name TEXT NOT NULL, text TEXT NOT NULL, fixed TINYINT NOT NULL, " & _ 
     "FOREIGN KEY(project_id) REFERENCES Projects(ProjectID) ON DELETE CASCADE);" 
+1

Faites toutes vos colonnes de clé étrangère ont un indice sur eux? Sinon, l'ajout d'un index devrait accélérer la suppression. – GarethD

+0

Désolé, mais qu'entendez-vous par «avoir un index sur eux»? Je vais ajouter la déclaration de la table à ma question. – Jens

Répondre

5

Le documentation dit:

indices ne sont pas nécessaires pour les enfants colonnes clés, mais ils sont presque toujours bénéfique. [...]

Chaque fois qu'une application supprime une ligne de la table parent ..., elle exécute [une requête] pour rechercher les lignes de référence dans la table enfant.

Si cette requête renvoie des lignes, SQLite conclut que la suppression de la ligne de la table parent viole la contrainte de clé étrangère et renvoie une erreur. Des requêtes similaires peuvent être exécutées si le contenu de la clé parent est modifié ou si une nouvelle ligne est insérée dans la table parente. Si ces requêtes ne peuvent pas utiliser un index, elles sont obligées d'effectuer une analyse linéaire de la table enfant entière. Dans une base de données non triviale, cela peut être prohibitif. Par conséquent, dans la plupart des systèmes réels, un index doit être créé sur les colonnes de clé enfant de chaque contrainte de clé étrangère. L'index de clé enfant n'a pas à être (et ne sera généralement pas) un index UNIQUE.

Vous devez créer des index sur les enfants colonnes clés:

CREATE INDEX Groups_project_id_index ON Groups(project_id); 
+0

Ahkay, est-ce que je fais ceci avant ou après avoir ajouté des données aux tables? Comme je crée la table et ajoute immédiatement cet index? (Je vais devoir lire sur ce sujet, puisque je n'en ai jamais entendu parler auparavant :-)) – Jens

+0

Je l'ai ajouté juste après la création de la table et ça marche beaucoup plus vite maintenant. Je vous remercie! – Jens

Questions connexes