Home > Artikel > Ausgabe 6/2016 > Datenbanken von Altlasten säubern

Datenbanken von Altlasten säubern

Achtung: Sie sind nicht angemeldet. Wenn Sie Abonnent sind und sich anmelden, lesen Sie den kompletten Artikel, laden das PDF herunter oder probieren die Beispieldatenbank aus (sofern vorhanden).

Dass sich Access-Datenbanken mit der Zeit aufblähen, dürfte jedem Entwickler einmal aufgefallen sein. Beim Löschen von Daten und Objekten, dem Importieren von Objekten aus anderen Datenbanken, Modifikationen an Modulen, dem Überschrieben von Objekten, fällt Müll an, der oberflächlich nicht sichtbar ist. Über die Ribbon-Funktion Komprimieren und Reparieren kann aber ein Teil dieses Mülls leider nicht entfernt werden. Mit recht überschaubarem VBA-Code ändert sich das.

Beispieldatenbank

Die Beispiele dieses Artikels finden Sie in der Datenbank 1606_Saeubern.accdb.

Temporäre Datenbankobjekte

Access-Datenbanken können sowohl Tabellen, wie Abfragen, enthalten, die Sie im Navigationsbereich nicht zu Gesicht bekommen. Auf diese möchten wir hier den Fokus setzen.

Die Beispieldatenbank implementiert vier relational verknüpften Tabellen zu Kundenadressen. Auf diese setzt das Formular frmKunden auf (Bild 1). Die Haupttabelle tblKunden steht für die Datenherkunft des Formulars, die Detailtabellen tblAnreden, tblOrte und tblLaender werden für die Kombinationsfelder verwendet. Die Steuerelemente kamen durch einfaches Hineinziehen der Vorhandenen Datenfelder zustande. Kombinationsfelder ergeben sich deshalb, weil für die Felder IDAnrede, IDOrt und IDLand im Entwurf von tblKunden jeweils Nachschlagetabellen angegebenen wurden. Also füllt Access hier im Eigenschaftenblatt neben dem Steuerelementinhalt auch gleich die passenden Quelltabellen ein und verknüpft die Felder, wie dies aus der Abbildung hervorgeht.

Das Kundenformular enthält drei Kombinationsfelder, deren Datenherkunft auf den entsprechenden Detailtabellen basiert

Bild 1: Das Kundenformular enthält drei Kombinationsfelder, deren Datenherkunft auf den entsprechenden Detailtabellen basiert

Grundsätzlich legt Access nun beim Speichern sowohl für das Formular, wie auch für Kombinations- und Listenfelder intern Abfragen an, die weder im Navigationsbereich, noch im Formularentwurf in Erscheinung treten. Doch öffnen Sie einmal die Systemtabelle MSysObjects, die einen Katalog aller Datenbankobjekte verzeichnet. Bild 2 zeigt, dass hier vier Abfragen zu sehen sind. Sie werden durch die Spalte Type identifiziert, wenn diese den Wert 5 aufweist. Für die Namen der Abfragen ist jeweils das Präfix ~sq_ spezifiziert. Folgt darauf ein f, so handelt es sich um die Datenherkunft eines Formulars. Access verwendet also nicht die Tabelle tblKunden selbst, sondern eine auf ihr beruhende Abfrage für die Daten des Formulars. Der Name des Formulars schließt sich daran an. Für die Datenherkunft von Kombinationsfeldern steht eine ~sq_c...-Abfrage. Ihr folgt der Name des Formulars, in dem sich das Kombinationsfeld befindet, und schließlich der Name des Steuerelements, ebenfalls durch ein ~sq_c-Präfix gekennzeichnet.

In der Systemtabelle MSysObjects finden sich die versteckten Abfragen für die Kombinationsfelder des Formulars, beginnend jeweils mit dem Präfix ~sq_

Bild 2: In der Systemtabelle MSysObjects finden sich die versteckten Abfragen für die Kombinationsfelder des Formulars, beginnend jeweils mit dem Präfix ~sq_

Diese Abfragen sind über die Oberfläche nicht zu erreichen, wohl aber über DAO! Geben Sie so etwa den SQL-String für die dem Anrede-Steuerelement zugrundeliegende Abfrage im VBA-Direktfenster aus:

  CurrentDB.QueryDefs _

(" ~sq_cfrmKunden~sq_cIDAnrede").SQL

Sie erhalten dieses Ergebnis:

SELECT DISTINCTROW *

FROM tblAnreden;

Das Formular hat diese Datenherkunft:

  CurrentDB.QueryDefs _

   ("~sq_ffrmKunden").SQL

> "SELECT DISTINCTROW *

FROM tblKunden;"

Das DISTINCTROW sagt der Database Engine, dass die zurückgelieferten Datensätze eindeutig sein sollen. Das ist an sich überflüssig, da die Tabellen allesamt einen Primärschlüssel aufweisen.

Entfernten Sie diesen später aber, so könnten auch doppelte identische Datensätze in ihr abgespeichert werden. Hier bekommt das DISTINCTROW dann einen Sinn.

Diese internen Abfragen sind übrigens nicht schreibgeschützt. Sie können ihren SQL-Ausdruck problemlos ändern; etwa so:

CurrentDB.QueryDefs _

   ("~sq_ffrmKunden").SQL = _

"SELECT * FROM tblKunden"

Diese Änderung bleibt auch nach Modifikationen am Formularentwurf erhalten! Es versteht sich von selbst, dass Sie hier nicht unsinnige Ausdrücke einsetzen sollten, um Probleme zu vermeiden.

Was hat dies alles aber mit dem Müll zu tun, von dem eingangs die Rede war? Leider kommt es vor, dass besonders bei Formularen, die Sie aus anderen Datenbanken importierten, die auf sie bezogenen internen Abfragen nicht ordnungsgemäß gelöscht werden, wenn sie selbst entfernt werden. Damit finden sich verwaiste ~sq-Einträge in der Systemtabelle MSysObjects, und auch deren Spezifikationen in MSysQueries bleiben bestehen. Das bläht die Datenbank auf, wenn auch in bescheidenem Umfang.

Schwerwiegender jedoch ist ein anderer Sachverhalt. Löschen Sie Objekte im Navigationsbereich über die Taste ENTF, so läuft alles glatt. Verwenden Sie aber STRG-ENTF, wie Sie es eventuell aus dem Explorer gewohnt sind, um Dateien nicht in den Papierkorb zu transferieren, sondern endgültig zu löschen, so verhält sich Access etwas eigentümlich. Scheinbar ist das Objekt nun gelöscht, findet sich aber trotzdem noch in MSysObjects. Das ändert sich in der Regel erst, nachdem Sie die Datenbank schließen oder komprimieren. Machen Sie dazu folgendes Experiment.

Markieren Sie drei Tabellen, wie in Bild 3. Kopieren Sie diese über das Kontextmenü oder über STRG-C und fügen Sie sie als Kopien wieder in die Datenbank ein. Access fragt Sie dabei nach dem Namen der einzufügenden Tabellen. Belassen Sie es bei den Voreinstellungen, wodurch es zu den Einträgen in Bild 4 kommt. Markieren Sie die neuen Tabellen und drücken nun STRG-ENTF. Die Tabellen scheinen nun gelöscht worden zu sein.

Markieren dreier Tabellen

Bild 3: Markieren dreier Tabellen

Kopierte Tabellen

Bild 4: Kopierte Tabellen

Tatsächlich hat Access sie jedoch lediglich umbenannt. Ein Blick in MSysObjects zeigt sie mit kryptischen Namen, die alle mit ~TMPCLP beginnen (siehe Bild 5). Die Spalte Type identifiziert sie über den Wert 1. Ihr Ursprung ist indessen nicht mehr auszumachen. Beim Schließen der Datenbank entfernt Access diese temporären Tabellen. Auch andere Objektarten erhalten übrigens dieses Präfix. Leider bleibt dieser Löschvorgang unter Umständen aus. Stürzt Access etwa beim Ausführen vom API-Anweisungen ab, so verbleiben die temporären Objekte für ewig in der Datenbank. Welche anderen Ursachen es hat, dass dieser Aufräumvorgang nicht ausgeführt wird, ist nicht dokumentiert. Tatsächlich passiert dies nach unseren Beobachtungen öfter, als nur beim Absturz von Access. Natürlich bläht sich die Datenbank nur deutlich mehr auf, als das bei den internen Abfragen der Fall ist. Auslösend für diesen Beitrag war nämlich die Tatsache, dass die Beispieldatenbank bei Entwicklung plötzlich eine Größe von 16 MB hatte. Komprimieren und Reparieren half nicht. Ursache waren Experimente mit den VBA-Anweisungen ExportXML und ImportXML, die an anderer Stelle beschrieben werden. Die Kundentabelle fand sich mehrfach als ~TMPCLP-Objekte in der Datenbank!

Die per STRG-ENTF gelöschten Tabellen existieren immer noch

Bild 5: Die per STRG-ENTF gelöschten Tabellen existieren immer noch

Temporäre Objekte löschen

Das Löschen dieser verwaisten Objekte ist denkbar einfach. Es braucht dafür nur die Routine CleanDB, die Sie im Modul mdlSaeubern der Beispieldatenbank finden. Zeigen sich bei Inspektion der Tabelle MSysObjects in Ihrer Datenbank solche verwaisten Objekte, so importieren Sie die Routine einfach in Ihre Datenbank. Bei ihrer Ausführung kann nichts kaputt gehen.

Sie haben das Ende des frei verfügbaren Teil dieses Artikels erreicht!

Wenn Sie mehr lesen und auf viele weitere Artikel zugreifen möchten, melden Sie sich als Abonnent unter Login an. Falls nicht, bestellen Sie doch einfach ein Jahresabonnement!