Warsztat Acc97: Automatyczna defragmentacja bieżącej bazy przy wyjściu z aplikacji.

Defrag.zip (defragmentacja z wykorzystaniem drugiej instancji Accessa)
Autor: Krzysztof Pozorek
23kB, 04-05-2000
Royally Free
 
Defrag3.zip (defragmentacja z własnego menu)
Autor: Krzysztof Pozorek
23kB, 19-02-2001
Royally Free
 
Obie bazy są w formacie MsAccess 97

Opis problemu:

Każda baza MsAccess z czasem 'puchnie'. Jest to normalny efekt operacji tymczasowych, które w Accessie działają tak, że zajmują przestrzeń, a potem jej nie zwalniają. Nawet kasowanie rekordów (lub całych obiektów, jak np. tabele) nie zmniejsza romiaru bazy, tylko markuje je jako usunięte. Defragmentacja usuwa zalegające resztki i przywraca nominalny rozmiar pliku MDB.

Istnieje jednak pewien problem, który wprawdzie został usunięty w Accessie 2000, jednak ciągle dotyczy wcześniejszych wersji. Access 97 nie pozwala na defragmentację bieżącej bazy z poziomu kodu. To istotna wada, bo od czasu do czasu każdą bazę należy zdefragmentować. Można wprawdzie gdzieś na pulpicie zrobić dodatkową ikonkę, która po kliknięciu wywoła defragmentację bazy, ale... Po pierwsze nie jest to zawsze możliwe ani wygodne (np. gdy wysyłamy bazę w postaci pliku bez instalacji), a po drugie praktyka uczy, że jeśli nie można tej opcji zawrzeć w programie, to użytkownik nie będzie o niej pamiętał ani jej używał. Zwłaszcza, że dla niego efekt działania defragmentacji jest raczej mało zrozumiały, skoro po niej wszystko tak samo działa jak wcześniej.

Jednak każdy, kto pisze w Accessie wie, że defragmentacja redukuje rozmiar bazy, przyśpiesza jej działanie i zwiększa niezawodność aplikacji. A zatem jest użyteczna i warto ją stosować. Zostaje tylko pytanie, jak zdefragmentować bazę, którą właśnie używamy?

Rozwiązanie:

Mimo, że nie spotkałem się z idealną metodą defragmentacji bieżącej bazy w Accessie 97, to jednak jest kilka sposobów, które w lepszy lub gorszy sposób radzą sobie z tym problemem.
  1. Metoda wykorzystująca drugą instancją Accessa.
    Program Defrag.zip jest roboczym pomysłem, który dokonuje automatycznej defragmentacji bazy przy zamykaniu aplikacji. Działa na zasadzie wywołania ukrytej sesji Accessa, która przejmuje kontrolę nad naszą bazą i dokonuje jej defragmentacji. Dodatkowo, żeby ładnie wyglądało, program ukrywa ekran startowy Accessa. Robi się to budując plik BMP o wielkości 1 piksela i o takiej samej nazwie jak otwierana baza. Niestety program w tej wersji wymaga, żeby baza była bez hasła.
     
  2. Metoda (dość rozbudowana ) znaleziona na stronach Dev Ashisha. Jest to dodatek AddIns o nazwie compacter.mda, który umożliwia defragmentację bieżącej bazy oraz ponowne jej otworzenie i dalszą pracę aplikacji.
     
  3. Metoda, oparta na wykorzystaniu pliku BAT, opisywana kilkukrotnie w grupie dyskusyjnej pl.comp.bazy-danych.msaccess. Plik BAT należy przygotować wcześniej i wywołać na zakończenie naszej aplikacji w następujący sposób:
    call Shell("C:\defrag.bat", 0)
    
    DoCmd.Quit
    Nie trudno się domyśleć, co taki plik BAT powinien zawierać, ale dla porządku przytoczmy jego przykładową zawartość:
    C:\OFFICE\MSACCESS.EXE  D:\Bazy\Baza.mdb /compact
    
    C:\OFFICE\MSACCESS.EXE  D:\Bazy\Baza.mdb
    Można także budować plik BAT dynamicznie, pozwoli to nam uniezależnić się od nazwy bazy i konfiguracji Accessa. Funkcja SysCmd(acSysCmdAccessDir) określa katalog, w którym znajduje się plik msaccess.exe, a CurrentDb.Name zwraca nazwę bieżącej bazy danych. Oto przykładowa procedura defragmentacji bieżącej bazy oparta na dynamicznie budowanym pliku BAT:
    Dim temp, NumPliku
    
    NumPliku = FreeFile
    
    Open "C:\defrag.bat" For Output As #NumPliku
    
    Print #NumPliku, """" & SysCmd(acSysCmdAccessDir) & "MSACCESS.EXE "" """ & CurrentDb.Name & """ /compact "
    
    Print #NumPliku, """" & SysCmd(acSysCmdAccessDir) & "MSACCESS.EXE "" """ & CurrentDb.Name & """"
    
    Close #NumPliku
    
    temp = Shell("C:\defrag.bat", 0)
    
    DoCmd.Quit

    To prosty sposób, ale ma wadę: Niezbyt ładnie wygląda takie automatyczne zamykanie i otwieranie kolejnych instancji Accesa.

  4. Metoda, wykorzystująca opcję defragmentacji, dostępną z menu Accessa. Jak wiadomo opcja ta potrafi zdefragmentować bieżącą bazę, ale tylko wtedy, jeśli zostanie wywołana bezpośrednio z menu, a nie z programu. Spotkałem się z pomysłem, że można wysłać sekwencję klawiszy za pomocą akcji SendKeys, która będzie symulowała naciśnięcie odpowiedniej opcji menu. Opcja raczej z dziedziny 'ratuj się kto może', ale przy pewnych założeniach jest do przyjęcia. Osobiście jednak odradzam stosowanie SendKeys wszędzie tam, gdzie można tego uniknąć ze względu nieprzewidywalność takich działań przy różnych konfiguracjach Accessa.

    Jest inny sposób wywołania tej opcji, bez SendKeys. Metoda polega na tym, że budujemy własny pasek narzędziowy i wyświetlamy go w taki sposób, żeby wyglądał trochę jak formularz z przyciskami poleceń. To moja ulubiona metoda defragmentacji bieżącej bazy. Przykład Defrag3.zip pokazuje jak prosto wykonać taką opcję w praktyce.

Powyższe metody raczej nadają się do baz bez hasła i pracujących w środowisku pełnego Accessa (nie w Run-Time). Zdarzyło mi się stosować różne procedury defragmentacji w zależności od tego, w jakim trybie wywołano program. Dla pełnego Accessa stosowałem sposób podany w przykładzie Defrag3.zip, a w trybie Run-Time używałem metody z pliku Defrag.zip. Jak w kodzie wykryć tryb Run-Time podałem w dziale Anti-FAQ: Baza danych (pkt. 3).

Krzysztof Pozorek