Julian von Mendel: Dateibasiertes Speichern großer Datenmengen

Hi!

Ich möchte ein Schülerverwaltung mit ca. 2500 Schülern und jeweils ca. 70 Informationen aufbauen (also z. B. Geburtsdatum, Wohnort usw.). Es steht keine Datenbank zur Verfügung, es soll alles dateibasiert laufen. Wie speichere ich diese Daten mit möglichst wenig Aufwand und sehr hoher Performance?

Vielen Dank
Julian

--
"Wer in die Fußstapfen anderer tritt, hinterlässt selbst keinen Eindruck." - Christiane Weinhold
  1. hi,

    Ich möchte ein Schülerverwaltung mit ca. 2500 Schülern und jeweils ca. 70 Informationen aufbauen (also z. B. Geburtsdatum, Wohnort usw.). Es steht keine Datenbank zur Verfügung, es soll alles dateibasiert laufen. Wie speichere ich diese Daten mit möglichst wenig Aufwand und sehr hoher Performance?

    in dem du an dem punkt

    Es steht keine Datenbank zur Verfügung

    abhilfe schaffst.

    gruß,
    wahsaga

    --
    "Look, that's why there's rules, understand? So that you _think_ before you break 'em."
  2. Hello,

    schau Dir das noch nicht ganz ferige Beispiel der "Adressverwaltung" unter http://selfhtml.bitworks.de an. Da kannst Du auch 10.000 Schüler ohne DBMS verwalten, wenn Du Lust hast. Nur das Problem der Indexierung (damit die absoluten Satznummern gegen logische getauscht werden können) musst Du noch selber lösen.

    Harzliche Grüße aus http://www.annerschbarrich.de

    Tom

    --
    Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
    Nur selber lernen macht schlau
    1. Hi!

      schau Dir das noch nicht ganz ferige Beispiel der "Adressverwaltung" unter http://selfhtml.bitworks.de an. Da kannst Du auch 10.000 Schüler ohne DBMS verwalten, wenn Du Lust hast.

      Danke, dank dir hab ich es in 30min geschafft die Performance meines Programms extrem zu steigern (ganz ehrlich...hab davor eine ziemlich schlechte Lösung gehabt, die schon bei 300 Schülern Probleme gemacht hat).

      Nur das Problem der Indexierung (damit die absoluten Satznummern gegen logische getauscht werden können) musst Du noch selber lösen.

      Das verstehe ich nicht.

      Schöne Grüße
      Julian

      --
      "Wer in die Fußstapfen anderer tritt, hinterlässt selbst keinen Eindruck." - Christiane Weinhold
      1. Hello,

        Danke, dank dir hab ich es in 30min geschafft die Performance meines Programms extrem zu steigern (ganz ehrlich...hab davor eine ziemlich schlechte Lösung gehabt, die schon bei 300 Schülern Probleme gemacht hat).

        Nur das Problem der Indexierung (damit die absoluten Satznummern gegen logische getauscht werden können) musst Du noch selber lösen.

        Das verstehe ich nicht.

        Eine Datenbank hat auf den Zugriffswegen unterschiedliche Schichten. In meinem Beispiel habe ich nur die Ankoppeltung an die Hardwareschicht betrieben. Dort wird mit der physischen Datensatznummer gearbeitet, also die Nummer aus der Position in der Datei ermittelt. das Funktionierit nur bei Einzelplatzanwendungen zuverlässig. Bei konurrierendem Betrieb muss man die physische Nummer geben eine logische austauschen. Die ID ist dann nicht mehr berechenbar, sondern sie gehört zu den Metadaten des Datensatzes. Der Datenbank-User mus oder sollte gar keinen direkten Zugriff auf dieses Datenfeld des Satzes haben. Wenn der Satz nun verschoben wird, dann nimmt er die Nummer mit. Die Nummer ist dann also keine Adresse mehr, sondern ein Name.

        Nun muss man aber trotzdem noch wieder die Adresse des Datensatzes ermitteln können, damit man ihn holen lassen kann. Das macht man eben über eine Indexierung. Man schreibt eine geordnete Liste, in der Die Adresse des Satzes dem Namen gegenübergestellt wird. Diese Liste ist im einfachsten Fall durch binäre Suche durchsuchbar. Da kann man Einen aus Tausend dann eben mit maximal 10 Zugriffen ausfindig machen, oder eben Einen aus 4096 mit 12 Zugriffen.

        Wenn Du nun also die nächsten Wrapper für die bereits vorhandenen Funktionen schreibst (Select Record, Update Record, Delete Record, Insert Record und Show Empty Form) dann benötigst Du eine Funktion für Get_Next_ID() (also quasi einen Counter) und eine für InsertIndex, DeleteIndex, FindIndex, UpdateIndex...  Und sicherheitshalber eine ReIndex()-Funktion

        Die get_next_id() hänge ich hier dran...

        <?php   ### get_autokey.php ###

        #------------------------------------------------------------------------------

        Funktion softlock()

        #------------------------------------------------------------------------------

        Datei im Lock Modus $lockmode öffnen und Handle zurückgeben

        W, WRITE  = Lock Exclusive und (rb+)

        R, READ   = Lock Shared    und (rb)

        C, Create = Try to Create and lock exclusive (xb+)

        function softlock( $lockfile_name,             ## Qualifizierter Dateiname                    $mode,                      ## Öffnungs- und Sperranforderung                    &$lastwrite,                ## Letztes Aktualisierungsdatum                    &$error_no                  ## Duchgeschleifter Fehler                  ) {   $php_errormsg ='';                           ## ist nicht angelegt, solange                                                ## kein Fehler auftrat   $lastwrite = false;                          ## kein Modifikationsdatum vorhanden

        if ($error_no > 0) return false;             ## Bei Vorfehler abbrechen

        ## Lockmode feststellen   $lockmode = strtoupper($mode);

        if ($mode == 'W')   {     $openmode = 'rb+';     $lockmode = LOCK_EX;   }   elseif ($mode == 'C')   {     $openmode = 'xb+';     $error_no = 8;                               ## Datei wurde angelegt     $lockmode = LOCK_EX;   }   elseif($mode == 'R')   {     $openmode = 'rb';     $lockmode = LOCK_SH;   }   else   {     $error_no = 100;                             ## falsche Funktionsnutzung     return false;   }

        ## Dateihandle beschaffen

        for ($x=0;$x<5;$x++)                           ## Schleife 5 mal durchlaufen   {     clearstatcache();     $php_errormsg = '';

        if($lh = @fopen($lockfile_name,$openmode))     {       $error_no = 0;       break;                                     ## oder bei Erfolg abbrechen     }     else     {       $errormsg = strtolower($php_errormsg);

        if(strpos($errormsg,'invalid argument')!==false)       {         $error_no = 101;                         ## hier könnte man auch überlegen         $openmode = 'a+';                        ## es doch mit rb+ zu versuchen

        if ($fh1 = fopen($lockfile_name,$openmode))         {           $openmode = 'rb+';                     ## es doch mit rb+ zu versuchen           fclose($fh1);                          ## Hilfshandle wieder abgeben           $error_no = 8;         }         else         return false;       }       elseif(strpos($errormsg,'illegal operation argument')!==false)       {         $error_no = 101;         $openmode = 'a+';                        ## Datei hilfsweise mit a+ anlegen

        if ($fh1 = fopen($lockfile_name,$openmode))         {           $openmode = 'rb+';                     ## es doch mit rb+ zu versuchen           fclose($fh1);                          ## Hilfshandle wieder abgeben           $error_no = 8;         }         else         return false;       }       elseif(strpos($errormsg,'no such file or directory')!==false)       {         $error_no = 2;         return false;       }       elseif(strpos($errormsg,'permission denied')!==false and $error_no == 8)       {         return false;              ## damit Fehler 8 überhaupt nach draußen kommt       }       elseif(strpos($errormsg,'permission denied')!==false)       {         $error_no = 5;         return false;       }       elseif(strpos($errormsg,'file exists')!==false)       {         $openmode = 'rb+';       }     }     ## zur Zeit sind fopen() und dio_open() noch nicht aufeinander abgestimmt     ## Eine Verzögerung beim Öffen ist daher noch nicht sinnvoll

        #usleep(8000);                               ## 8ms warten bis zum nächsten   }                                              ## Öffnungsversuch

        if (!$lh)   {     $error_no = 5;                               ## konnte Datei nicht öffnen     return false;                                ## bei Misserfolg Funktionsende   }

        # Lockversuch   for ($x=0;$x<5;$x++)   {     if (@flock($lh,$lockmode + LOCK_NB))     {       $lastwrite = filemtime($lockfile_name);    ## letzes Modifikationsdatum       return $lh;     }     usleep(8000);  ## 8ms warten bis zum nächsten Versuch   }

        $error_no = 6;                                 ## konnte Datei nicht sperren   fclose($lh);   return false; } #------------------------------------------------------------------------------

        Ermittelt die nächste Unique-ID für einen Filenamen

        #------------------------------------------------------------------------------

        function get_autokey($keyfilename,    ## Name der Schlüsseldatei,                      $indexname,      ## Name der Datei, für deren DS der Schlüssel                      &$error_no)      ## Fehlernummer {

        if (strlen($indexname)==0 or is_numeric($indexname))   {     $error_no = 100;                  ## Function Misuse     return false;   }

        $indexname = strtolower($indexname);

        $fh = softlock($keyfilename,'C',$date,$error_no);  ## Schlüsseldatei öffen   if (!$fh) return false;

        $filesize = filesize($keyfilename);

        if ($filesize > 0)   {

        $keystream = fread($fh, $filesize);     if ($keystream === false)     {       $error_no = 4;                    ## read Error       fclose($fh);       return false;     }

        $_keyarr = unserialize($keystream);     if ($_keyarr === false or !is_array($_keyarr))     {       $error_no = 34;                   ## Decodierungsfehler       fclose($fh);       return false;     }   }   else $_keyarr = array();

        $_keyarr[$indexname]++;

        $keystream = serialize($_keyarr);   $streamlen = strlen($keystream);

        fseek($fh,0,SEEK_SET);   $write_ok = fwrite($fh,$keystream);

        if ($write_ok != $streamlen)   {     $error_no = 33;                   ## Schreibfehler     fclose($fh);     return false;   }

        ftruncate($fh,$streamlen);   fclose($fh);

        return $_keyarr[$indexname]; }

        #------------------------------------------------------------------ $date=0; $error = 0; $lockfile ='index.idx'; $filename ='ADRESSEN';

        echo "Nächster Schlüssel für <b>$filename</b> lautet ".get_autokey($lockfile,$filename,$error).'<br />';

        echo "Fehler lautet $error <br />";

        $lockfile ='index.idx'; $filename ='Rosen';

        echo "Nächster Schlüssel für <b>$filename</b> lautet ".get_autokey($lockfile,$filename,$error).'<br />';

        echo "Fehler lautet $error <br />";

        $lockfile ='index.idx'; $filename ='Aufgaben';

        echo "Nächster Schlüssel für <b>$filename</b> lautet ".get_autokey($lockfile,$filename,$error).'<br />';

        echo "Fehler lautet $error <br />";

        ?>

        Harzliche Grüße aus http://www.annerschbarrich.de

        Tom

        --
        Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen Nur selber lernen macht schlau
  3. Hallo Julian,

    Ich möchte ein Schülerverwaltung mit ca. 2500 Schülern und
    jeweils ca. 70 Informationen aufbauen (also z. B. Geburtsdatum,
    Wohnort usw.). Es steht keine Datenbank zur Verfügung, es soll
    alles dateibasiert laufen. Wie speichere ich diese Daten mit
    möglichst wenig Aufwand und sehr hoher Performance?

    Hört sich ganz nach einem Fall für B-Baum-Algorithmen an:

    http://de.wikipedia.org/wiki/B-Baum

    Grüße,
     CK

    --
    Das Leben ist wie ein Kartenspiel: was dir gegeben wurde, ist vorbestimmt. Doch wie du damit spielst, ist deine Entscheidung.
    http://wwwtech.de/
  4. Hallo,

    danke an euch für die Hilfe! Jetzt geht's einwandfrei, und dank Toms langen Text und dem Link von Christian hab ich auch genug zum Lesen und Verstehen, fürs Wochenende zumindest :)

    Schöne Grüße
    Julian

    --
    "Wer in die Fußstapfen anderer tritt, hinterlässt selbst keinen Eindruck." - Christiane Weinhold