[PHP] Datenbankzugriff oder Dateicheck schneller?

groe

lo0l
ID: 134786
L
26 April 2006
224
16
Hi.

Ich möchte eine Datei speichern, deren Dateiname vorher zufällig generiert wird. Dafür soll allerdings zuerst überprüft werden, ob eine Datei mit dem generiertem Namen nicht schon existiert.

PHP:
do {
 $name = rand(100,999) . ".gif";
 // $condition = ?;
} while($condition);
Für diese Überprüfung ($condition) gibt es nun zwei Möglichkeiten. Einerseits kann ich per file_exists() überprüfen, ob es so eine Datei schon gibt.

PHP:
$condition = file_exists($name)
Andererseits speichere ich in der MySQL-DB sowieso schon die Dateinamen in einer Tabelle. Somit könnte ich hier auch überprüfen.

PHP:
$condition = (mysql_query("SELECT COUNT(id) FROM dateien WHERE name = '".$name."'") > 0);
Meine Überlegung ist also nur, was schneller geht. Eine Datenbankabfrage, von der man immer sagt sie sei ein "Geschwindigkeits-Engpass", oder ein Zugriff aufs Dateisystem?

Ich hoffe ich habe mich verständlich ausgedrückt, ansonsten einfach fragen ;)

LG
groe

Der Sourcecode ist natürlich n Beispiel, die Dateinamengenerierung läuft sonst anders...
 
Zuletzt bearbeitet:
Für diese Überprüfung ($condition) gibt es nun zwei Möglichkeiten. Einerseits kann ich per file_exists() überprüfen, ob es so eine Datei schon gibt.

ich gehe mal davon aus, dass file_exists() die schnellere methode ist. da die datenbank selbst auch in files abgespeichert ist, muss natürlich darauf zugegriffen werden. eine abfrage, ob das file existiert macht mysql dann sicherlich ohnehin - ergo müsste mysql nach meinem verständnis langsamer sein.

letzlich weiss ich es aber nicht 100%ig. ich würde aber für mich die file_exists-methode bevorzugen. rein von der übersichtlichkeit und verständlichkeit des quellcodes her. wenn du nichts grösseres mehr mit den files vor hast ausser schreiben und lesen, dann ist das vollkommen ausreichend. ich gehe dabei mal davon aus, dass es hier nicht um riesige mengen von dateien geht, oder?
 
eine abfrage, ob das file existiert macht mysql dann sicherlich ohnehin

Wie meinst du das? o_O
In der DB-Tabelle wird immer ein Eintrag erstellt sobald eine Datei erstellt wird und dieser Eintrag gelöscht, wenn ein Eintrag entfernt wird.

Übersichtlichkeit und Verständlichkeit sind was das angeht kein Problem. Der Code oben ist, wie gesagt, ein Beispiel-Code. Die echte Umsetzung ist objektorientiert und auch um einiges übersichtlicher ;)

ich gehe dabei mal davon aus, dass es hier nicht um riesige mengen von dateien geht, oder?
Genau darum gehts. Das ganze sollte auf viele Dateien optimiert sein.

Bei meiner Dateinamengenerierung gibts bis zu 60^5 verschiedene Möglichkeiten, somit ist es seeehr unwahrscheinlich, dass die Schleife noch ein zweites Mal ausgeführt wird. Trotzdem: Einmal wird pro Datei mindestens abgefragt und diese Abfrage sollte zeiteffizient sein.
 
Wie meinst du das? o_O
In der DB-Tabelle wird immer ein Eintrag erstellt sobald eine Datei erstellt wird und dieser Eintrag gelöscht, wenn ein Eintrag entfernt wird.
ja, und die bd-tabelle besteht mind. aus einem daten-file und einem index-file. diese zwei files müssen vom mysql-server geöffnet werden, gelesen und zum teil beschrieben ... sind also auch file-operationen.

Genau darum gehts. Das ganze sollte auf viele Dateien optimiert sein.
in diesem falle solltest du dir vielleicht ein anderes verfahren überlegen. spontan würde mir da als erstes ein einzelnes "file-file" einfallen. soll heissen: du schreibst die dateinamen in ein textfile und liest es am anfang in ein array oder includest es. damit minimierst du die dateioperationen auf 2 zugriffe (lesen/schreiben) und hast den gleichen effekt. ich denke, dass in_array() bzw. array_search() dann erheblich schneller sind als eine deiner oben genannten methoden ...

die methode ist halt nur etwas "unschön" und dirty...
 
Naja und dann bei jeder neuen Datei das "file-file" öffnen und hintendran den Dateinamen schreiben? Bei jedem Löschvorgang die komplette Datei durchsuchen und diesen einen Eintrag dann rauslöschen?

Abgesehen von der höheren Rechenzeit beim Erstellen und Löschen von Dateien würde diese Methode auch Probleme machen, wenn es dann mal viele tausend oder zehntausend Dateien gibt.

In der Form lohnt sich so ein "file-file" aus meiner Sicht also eher nicht.

Gäbe es denn noch eine andere effizientere Möglichkeit? Bzw. weiss jemand was genaues bezüglich der GEschwindigkeitsunterschiede von MySQL- und File-Operationen?

LG
groe
 
hmm, das ist nun die Frage wie alles aufgebaut ist, aber ich wüsste eine Lösung, wie MySQL schneller ist.
nimm als Tabellentyp Memory, dann steht es im Ram und der wird so oder so schneller sein, als die Festplatte, kannst ja als Rückfalmethode noch den file_exists check machen, wenn der server mal offline ging und daher die tabelle leer ist.
 
Hmm...

Also in der aktuellen Tabelle steht ja weit mehr als nur der Dateiname. Den Tabellentyp Memory sollte ich also auf eine neue Tabelle anwenden in der nur die Dateinamen stehen.

Wenn der Server mal offline geht, sind Tabellen vom Typ "Memory" also geleert? Dann müsste ich auch vor jedem Erstellen einer Datei überprüfen, ob die Tabelle leer ist. Und falls das der Fall ist, müsste man erst alle Dateinamen neu in diese Memory-Tabelle laden - was bei ein paar tausend Dateien schon zu rechenaufwändig und "cronjob-verdächtig" wäre^^

Bei Verwendung eines Cronjobs wird das Ganze allerdings nochmal komplizierter. Beim Erstellen einer Datei müsste überprüft werden, ob die Memory-Tabelle leer ist. Falls ja, soll das auch so bleiben, damit spätere Datei-Erstellungen das ebenfalls berücksichtigen können. Wenn die Memory-Tabelle leer ist, wird die file_exists()-Methode verwendet.

PHP:
$detect = mysql_query("SELECT COUNT(dateinamen) FROM memory_table");
if($detect <= 0) {
 do {
  $name = rand(100,999) . ".gif";
 } while(file_exists($name));  
}
else {
 do {
  $name = rand(100,999) . ".gif";
 } while(mysql_query("SELECT COUNT(dateiname) FROM memory_table WHERE dateiname = '" . $name . "'"));  
 mysql_query("INSERT INTO memory_table (`dateiname`) VALUES ('" . $dateiname . "')");
}
// Und hier dann der Eintrag in die normale MySQL-Tabelle


Da hier auf jeden Fall mal eine Abfrage einer Memory-Table und danach entweder noch min. eine weitere Abfrage einer Memory-Table oder min. ein Dateizugriff stattfindet, ist nun die Frage ob das wirklich so effizient ist...

Ich habe noch nie mit MySQL-Tabellen des Typs Memory gearbeitet, kann das also schwer beurteilen :/ Lohnt sich das in diesem Fall denn?
 
was ist wenn du einen unique key auf den dateinamen in der datenbank setzt ?

Nun überprüftst du nicht ob es den Dateinamen schon gibt sondern du versucht einfach den Datensatz zu schreiben.
Je nach dem was MYSQL dann zurück liefert kannste ja nen neuen namen generieren lassen.
 
Wie bereits geschrieben, das ist ein Beispielcode. Im echten Code verwende ich ein Array mit 60 Zeichen. Per Zufall werden jeweils 5 davon hintereinandergereiht und das als Dateiname verwendet wird. Somit ist bei 2000 Dateien die Wahrscheinlichkeit dass zum zweiten Mal ein Dateiname generiert werden muss 2000 zu 60^5 (777600000) also ~ 0,00025 %.

Und wie mache ich sowas, sodass es garantiert Unique ist? mmh... Ich könnte beispielsweise das aktuelle Datum und die Uhrzeit in den Dateinamen tun... Aber wie sieht denn das aus? :/
 
Nya garantiert einmalig ist es ja dann trotzdem nicht^^

Wobei das md5 ja auch nicht nötig ist. Ausserdem sieht das ja einfach nicht gut aus, wenn da so ne lange Zahl im Dateinamen steht :/

So langsam tendier ich dazu, diese geringen Geschwindkeitseinbusen zu akzeptieren und mich mit der bisherigen Lösung ála file_exists() abzufinden^^
 
:wall: wir reden hier von zeiten im millisekunden bereich... ob nun das überprüfen 8ms oder 10ms dauert ist doch wurscht. da brauch man weder ne extra datei anlegen, noch ne extra tabelle noch sonste was... je nach anwendung würde ich file_exists oder die db lösung nehmen. wenn ich nen große anwendung baue die eventuelle mal später auf verteilten systemen arbeiten soll würde ich die datenbank lösung nehmen, ansonsten würde ich zu file_exists greifen. bei der datenbank lösung sollte aber die tabelle entsprechend optimiert sein... bei einer gewissen größe sollte man den dateiname dann als index setzen. (was zu dem selbem ergebniss wie ne memory tabelle führen würde bloss bei weiten einfacher zu verwalten, handhaben und sonstiges ist)

andere ürberlegung wäre vielleicht die datein einfach nach dem datensatz zu bennen... zb du hast nen auto inc wert, den könntest du automatisch als dateiname nehme. wenn das zu "unsicher" ist kannste ja noch 2 bis 4 zeichen zufalls code anhängen den du mit in der datenbank speicherst.
 
Wie bereits geschrieben, das ist ein Beispielcode. Im echten Code verwende ich ein Array mit 60 Zeichen. Per Zufall werden jeweils 5 davon hintereinandergereiht und das als Dateiname verwendet wird. Somit ist bei 2000 Dateien die Wahrscheinlichkeit dass zum zweiten Mal ein Dateiname generiert werden muss 2000 zu 60^5 (777600000) also ~ 0,00025 %.

Und wie mache ich sowas, sodass es garantiert Unique ist? mmh... Ich könnte beispielsweise das aktuelle Datum und die Uhrzeit in den Dateinamen tun... Aber wie sieht denn das aus? :/
Ja und wenn du nun in deiner mysql tabelle auf dateiname nen unique key hast und versucht einen Datensatz anzulegen wo es den Dateinamen schonmal wo anders gibt. Dann würfte dir mysql nen FALSE zurückliefern wenn das auftritt dann halt nochmal die Schleife durchlaufen lassen.

nein ich meinte, einen unique dateinamen erstellen, der nicht schon einmal vorhanden sein kann, dann wäre das problem noch vor der wurzel erledigt...

oder so ^^.
Mann könnte ja auch den original dateinamen nehmen und bei diesem dann nach jedemn 2. buchstaben ein teil von md5(time()) einfügen.
Ok wie perfomancelastig das ist keine ahnung ^^.