php.de

Zurück   php.de > Webentwicklung > PHP-Fortgeschrittene

PHP-Fortgeschrittene Arbeiten mit PHP ohne Einschränkungen

Antwort
 
LinkBack Themen-Optionen Thema bewerten
Alt 15.12.2004, 10:44  
Gast
 
Beiträge: n/a
Standard [Erledigt] Große Arrays vergleichen

Moin,

ich hoffe die folgende Frage ist nicht zu popelig fürs Profis-Forum, falls doch - sorry!
Also, ich habe eine Seite für einen kleinen Lokalradiosender geschrieben. Dort kann über ein Formular einfach das Sendeprogramm eingegeben werden, indem man z.B. sagt dass man an jedem Werktag um 14 Uhr Nachrichten sendet. Das bedeutet also, wenn das Jahr 250 Werktage hat und man für ein Jahr im Voraus einträgt, dass in der Tabelle sendung_termin 250 Einträge erfolgen. Problem ist nun folgendes: Damit nicht zwei Termine zur gleichen Zeit eingetragen werden können erfolgt ein Check, ob zu einem der neuen Zeitpunkte bereits eine Sendung eingetragen ist.
Dieser Check erfolgt in einer Funktion, die die neuen Termine als Objekte in einem Array übergeben bekommt (die Objekte haben die Eigenschaften Timestamp_beginn, Timestamp_ende, Sendungs-ID), diese Funktion startet dann eine Datenbankabfrage und prüft mit einfachen if-Konstrukten, ob die Timestamps sich überschneiden. Was passiert brauche ich nun fast nicht mehr beschreiben, bei (worst case) 250 neuen Terminen und etwa 2700 bereits eingetragenen Terminen kommt der mit 90 Sekunden Laufzeit nicht hin, mal ganz abgesehen von der nicht vorhandenen Eleganz dieser Lösung. Leider fällt mir auch nichts besseres ein - hat jemand eine Idee?

Besten Dank und schöne Grüße,
Michael
  Mit Zitat antworten
Sponsor Mitteilung
PHP Code Flüsterer

Registriert seit: 21.08.2005
Beiträge: 4682
PHP-Kenntnisse:
Fortgeschritten

Alt 15.12.2004, 11:50  
Erfahrener Benutzer
 
Registriert seit: 18.07.2004
Beiträge: 2.162
PHP-Kenntnisse:
Fortgeschritten
Basti
Standard

Auf jeden Fall solltest du es vermeiden, für jeden Termin ein Objekt anzulegen. Das mag zwar nett aussehen, ist aber (vor allem in PHP4) einiges lahmer, als die Daten einfach in Arrays zu legen. Dann musst du die Tests in die DB auslagern. MySQL macht das für dich *g.

Basti
Basti ist offline   Mit Zitat antworten
Alt 15.12.2004, 15:38  
Gast
 
Beiträge: n/a
Standard

moin,

ich glaube am besten postetst du mal die methode die versucht rauszufinden ob die termine schon belegt sind. evtl kann mann das optimieren bzw vereinfachen.

gruss
Sike
  Mit Zitat antworten
Alt 15.12.2004, 17:23  
Gast
 
Beiträge: n/a
Standard Quellcode-Überfall

Danke erstmal, ich habe mich bemüht so deutlich wie möglich zu kommentieren.
Nochmal zu den Größenordnungen: Das Array $neueTermine hat max wenige hundert Objekte, die Datenbankabfrage kann aber durchaus bis zu 3000 Zeilen liefern. Wenn überhaupt kollidieren max. 10...20 Termine miteinander.

Danke und Gruß
Michael

Code:
/**
 * Prüft die Liste der neuen Termine auf Kollisionen
 *
 * Übergeben wird ein Array von sendung_termin-Objekten. Es wird dann 
 * untersucht, ob einer der neuen Termine mit einem bereits eingetragenen 
 * Termin kollidiert. Die kollidierenden Termine werden in einem Array 
 * zurückgegeben.
 * Falls diese Funktion bei der Änderung eines Termins aufgerufen wird, 
 * wird dessen Sid übergeben, um keine Kollision mit dem eigenen Termin 
 * anzuzeigen.
 *
 * @param Array Liste von sendung_termin-Objekten
 * @param Int Sid eines Termins, der geändert wird
 * @return Array Liste mit sendung_termin-Objekten der kollidierten 
 * Termine: (LNR = Laufende Nr) 
 * [LNR]['alt']=Alter Termin, [LNR]['neu']=neuer Termin
 */
 
function checkCollisions ($neueTermine, $auswahl = NULL) {
    //Datenbankabfrage für die in Frage kommenden Termine, die kollidieren könnten
    global $db;
    $ret = array();
    $index = 0;
    
    // Übergebenen Termin von Kollisioncheck ausschließen
    if ($auswahl != NULL) {
		$not_sid = " WHERE Sid != $auswahl";
    }//if
    
    //Ersten und letzten Termin holen
    $maxIndex  = count($neueTermine) - 1;
    $last_beg  = $neueTermine[$maxIndex]->getTS_ende();
    $first_beg = $neueTermine[0]->getTS_beginn();

    $sql = "SELECT * FROM sendung_termin WHERE TS_beginn >= $first_beg AND TS_ende <= $last_beg{$not_sid} ORDER BY TS_beginn";
    $query = $db->query($sql);

    if (DB::iserror($query)) {
		echo "Fehler bei Datenbankabfrage.";
		logError(__FILE__, __LINE__, $query->getMessage()." , SQL: $sql");
		return 0;
    }//if

	//Alle Zeilen der Datenbankabfrage durchgehen...
    while ($row = $query->fetchRow()) {
		$beg  = $row->TS_beginn;
		$ende = $row->TS_ende;
		
		//... und mit allen neuen Terminen auf Kollisionen prüfen
		foreach ($neueTermine as $ntermin) {
			//Timestamps für beginn und Ende in Var speichern
			$n_beg  = $ntermin->getTS_beginn();
			$n_ende = $ntermin->getTS_ende();
	
			/* ### Nun werden alle möglichen Fälle geprüft ### */
			
			/* 1. Neue Sendung beginnt nach einer eingetragenen und endet vor deren ende
		
				 +---------------+
				 |  Eingetragene |
				 +---------------+
			
					  +--------+
					  |  Neue  |
					  +--------+
			*/
	
			if ($n_beg >= $beg && $n_beg < $ende) {
				// Wenn der abgefragte Fall erfüllt ist wird im Rückgabearray ein neues Objekt des Termins erzeugt, der kollidiert
				$ret[$index]['alt'] = &new sendung_termin($row->Sid);	//Objekt erzeugen
				$ret[$index]['alt']->setLnr($row->Lnr);					// Index vergeben (Schlüssel der Objekte sind SID und LNR)
				$ret[$index]['alt']->getAllFromDb();					//Das Objekt holt seine Daten aus der DB
				$ret[$index]['neu'] = $ntermin;							//Der neue Termin, damit man weiß welcher alter mit welchem neuen Termin kollidiert
				$index++;
			}//if
			
			/* 2. Neue beginnt vor einer Eingetragenen und endet nach deren Beginn
				
				 +---------------+
				 |  Eingetragene |
				 +---------------+
			
			  +--------------+
			  |    Neue      |
			  +--------------+
			*/
	
			elseif ($n_beg <= $beg && $n_ende > $beg) {
				$ret[$index]['alt'] = &new sendung_termin($row->Sid);
				$ret[$index]['alt']->setLnr($row->Lnr);
				$ret[$index]['alt']->getAllFromDb();
				$ret[$index]['neu'] = $ntermin;
				$index++;
			}//if
			
			/* 3. Neue beginnt vor dem Ende einer eingetragenen und endet danach
		
				 +---------------+
				 |  Eingetragene |
				 +---------------+
			
					  +--------------+
					  |    Neue      |
					  +--------------+
			*/
			
			elseif ($n_beg < $ende && $n_ende >= $ende) {
				$ret[$index]['alt'] = &new sendung_termin($row->Sid);
				$ret[$index]['alt']->setLnr($row->Lnr);
				$ret[$index]['alt']->getAllFromDb();
				$ret[$index]['neu'] = $ntermin;
				$index++;	    
			}//if
					
			/* 4.  Neue beginnt vor einer Eingetragenen und endet nach deren Ende
		
				 +---------------+
				 |  Eingetragene |
				 +---------------+
			
			   +--------------------+
			   |        Neue        |
			   +--------------------+
			*/
			
			elseif ($n_beg <= $beg && $n_ende >= $ende) {
				$ret[$index]['alt'] = &new sendung_termin($row->Sid);
				$ret[$index]['alt']->setLnr($row->Lnr);
				$ret[$index]['alt']->getAllFromDb();
				$ret[$index]['neu'] = $ntermin;
				$index++;
			}//if
		}//foreach
    }//while
    return $ret;
    
}//checkCollisions
  Mit Zitat antworten
Alt 15.12.2004, 17:49  
Gast
 
Beiträge: n/a
Standard Re: Große Arrays vergleichen

Zitat:
Zitat von mbscholz
Dieser Check erfolgt in einer Funktion, die die neuen Termine als Objekte in einem Array übergeben bekommt (die Objekte haben die Eigenschaften Timestamp_beginn, Timestamp_ende, Sendungs-ID), diese Funktion startet dann eine Datenbankabfrage und prüft mit einfachen if-Konstrukten, ob die Timestamps sich überschneiden. Was passiert brauche ich nun fast nicht mehr beschreiben, ...
Nein.

Verwende für Beginn und Ende Datetime und gestalte die DB Abfrage so, daß MySQL die Termine zurückgibt, die mit dem neu einzutragenden Termin kollidieren. Die präsentierst Du dem Redakteur, zur weiteren Entscheidung. Da ja prinzipiell keine Überschneidungen möglich sein dürfen, kannst Du aus Beginn und Ende den Primary Key bilden. Dann wehrt sich MySQL gegen Fehleingaben.

Update bzw. delete gestaltest Du so, daß Du in der Where Klausel, die Du mit PHP zusammenbastelst, all die Termine angibst, die geändert werden müssen.

Theoretisch könnte das mit 3 Querys erledigt werden:
SELECT ... Ergenis zum Client und in die Session
Anzeige
DELETE ...
UPDATE ...
  Mit Zitat antworten
Alt 15.12.2004, 18:37  
Gast
 
Beiträge: n/a
Standard

nabend,

hab mir mal deine methode da angeschaut....
ich verstehe nicht ganz warum du mehrere hundert termine als parameter übergibts? ist das im endeffekt zb eine sendung die regelmässig innerhalb eines bestimmten zeitraums läuft? ändert sich da dann nur das datum, aber nicht die zeit? weil wenn das alles "einzelne" termine sind dann wird es wirklich etwas komplizierter (:

noch ne nebenfrage : welche php version benutzt du?

gruss
Sike
  Mit Zitat antworten
Alt 15.12.2004, 19:54  
Gast
 
Beiträge: n/a
Standard

Zitat:
Zitat von sike
nabend,

hab mir mal deine methode da angeschaut....
ich verstehe nicht ganz warum du mehrere hundert termine als parameter übergibts? ist das im endeffekt zb eine sendung die regelmässig innerhalb eines bestimmten zeitraums läuft? ändert sich da dann nur das datum, aber nicht die zeit? weil wenn das alles "einzelne" termine sind dann wird es wirklich etwas komplizierter (:
Jepp
Der Grund, jeden Termin einzeln zu speichern, ist, dass es auch Ausnahmen bei regelmäßigen Terminen gibt. z.B. läuft an Heiligabend nicht das normal Freitagsprogramm. Außerdem sind die Intervalle täglich, werktäglich, wöchentlich, 14-tägig, 4-wöchentlich... und zwei Mal im Jahr kommt ne Uhrenumstellung hinzu - ich sehe da keine andere Möglichkeit als mit einer Terminliste zu arbeiten. Ob die jetzt als Parameter übergeben werden muss und ob das Objekte sein müssen steht natürlich auf einem anderen Blatt...

Zitat:
noch ne nebenfrage : welche php version benutzt du?

gruss
Sike
4.3.4

Danke und Gruß
Michael
  Mit Zitat antworten
Alt 15.12.2004, 21:08  
Erfahrener Benutzer
 
Registriert seit: 18.07.2004
Beiträge: 2.162
PHP-Kenntnisse:
Fortgeschritten
Basti
Standard Re: Große Arrays vergleichen

Zitat:
Zitat von meikel
Da ja prinzipiell keine Überschneidungen möglich sein dürfen, kannst Du aus Beginn und Ende den Primary Key bilden. Dann wehrt sich MySQL gegen Fehleingaben.
Das kann natürlich nicht der einzige Test sein, da so überschneidungen ja nicht ausgeschlossen werden. Außerdem kannst du so ja nichtmehr auf die time & date Funktionen von MySQL zugreifen, denn das ist dann ja kein Zeitformat mehr. Und immer eine so große ID als Referenz anzugeben ist ja auch unnötig.

Zitat:
Update bzw. delete gestaltest Du so, daß Du in der Where Klausel, die Du mit PHP zusammenbastelst, all die Termine angibst, die geändert werden müssen.

Theoretisch könnte das mit 3 Querys erledigt werden:
SELECT ... Ergenis zum Client und in die Session
Anzeige
DELETE ...
UPDATE ...
Race Conditions beachten!

Ich glaube, es ist am sinnigsten, wenn du erst alle neuen Termine einfach in die Tabelle reinhaust. Diese braucht dazu noch ein Flag, ob ein Termin bestätigt ist oder ob er nur temporär abgelegt wurde. Das machst du in einer Insert-Query (Optimierung: http://dev.mysql.com/doc/mysql/en/Insert_speed.html). Dann updatest du in einer zweiten Query alle Datensätze mit bestätigt = 0, deren Termine nicht mit einem Datensatz mit bestätigt = 1 kollidieren und setzt diesen Wert auf 1. Im dritten und vierten Schritt liest du die ungültigen Termine aus und löscht diese wieder.

Basti

PS:
Sortierungen sind übrigends extreme Performance-Killer (falls du in etwa bei deinem alten Konstrukt bleiben magt).
Basti ist offline   Mit Zitat antworten
Alt 15.12.2004, 21:45  
Gast
 
Beiträge: n/a
Standard Re: Große Arrays vergleichen

Zitat:
Zitat von bbastix
Zitat:
Zitat von meikel
Da ja prinzipiell keine Überschneidungen möglich sein dürfen, kannst Du aus Beginn und Ende den Primary Key bilden. Dann wehrt sich MySQL gegen Fehleingaben.
Das kann natürlich nicht der einzige Test sein, da so überschneidungen ja nicht ausgeschlossen werden.
Bei einem Sendeplan gibt es keine Überschneidungen.

Zitat:
Außerdem kannst du so ja nichtmehr auf die time & date Funktionen von MySQL zugreifen, denn das ist dann ja kein Zeitformat mehr.
Ich schrieb: DateTime für Beginn und für Ende. Und ich schrieb auch, daß das Ergebnis der Termine, die mit der Abfrage kollidieren, zusätzlich in die Session sollen. Da der OP PEAR :: DB benutzt, kann er $db->getAll($sql) benutzen (ASSOC Modus)

Zitat:
Race Conditions beachten!
Entweder Tabelle sperren oder die gelesenen Records mit geeigneten Mitteln als 'in Bearbeitung befindlich' markieren oder eine SQL Queue in die DB Klasse einbauen, falls auf die Tabelle nur über das Script zugegriffen wird.

Man könnte dabei auch über einen *sql basierten session_save_handler nachdenken, damit Session 2 weiß, was Session 1 vorhat.
  Mit Zitat antworten
Alt 16.12.2004, 19:23  
Erfahrener Benutzer
 
Registriert seit: 18.07.2004
Beiträge: 2.162
PHP-Kenntnisse:
Fortgeschritten
Basti
Standard Re: Große Arrays vergleichen

Zitat:
Zitat von meikel
Zitat:
Zitat von bbastix
Zitat:
Zitat von meikel
Da ja prinzipiell keine Überschneidungen möglich sein dürfen, kannst Du aus Beginn und Ende den Primary Key bilden. Dann wehrt sich MySQL gegen Fehleingaben.
Das kann natürlich nicht der einzige Test sein, da so überschneidungen ja nicht ausgeschlossen werden.
Bei einem Sendeplan gibt es keine Überschneidungen.
Achso, ich hab dich so missverstanden, als wolltest du einafch Überschneidungen vermeiden, indem du aus Start- und Endzeit einfach eine ID generierst. Hab ich dich einfach falsch verstanden. Wär ja auch ein sonderbarer Denkfehlker gewesen.

Zitat:
Zitat:
Außerdem kannst du so ja nichtmehr auf die time & date Funktionen von MySQL zugreifen, denn das ist dann ja kein Zeitformat mehr.
Ich schrieb: DateTime für Beginn und für Ende. [...]
Ich dachte, diese ID (bestehend aus Start- und Endzeit) sollte die einzige Quelle für diese Zeitinformationen sein. Dann macht es aber doch mal mehr keinen Sinn, oder was versprichst du dir davon? Kostet doch nur (geringfügig) mehr Speicher, bringt aber doch keinen Netzen gegenüber einer fortlaufenden Nummer.

Basti
Basti ist offline   Mit Zitat antworten
Antwort


Themen-Optionen
Thema bewerten
Thema bewerten:

Forumregeln
Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are an
Gehe zu

Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
Mehrere Arrays summieren buggybugga PHP-Fortgeschrittene 8 22.07.2008 11:51
Mehrere Mehrdimensionale Arrays Stefano PHP Tipps 2006 5 12.10.2006 13:18
Arrays sortieren, Bezeichnung, Preis Ticos PHP Tipps 2006 4 07.09.2006 19:37
ausgelesene Werte im Array vergleichen - Möglich!? vampsoftchef PHP Tipps 2006 2 22.08.2006 14:34
Arrays vergleichen - Unterschiede löschen heohni PHP Tipps 2006 8 23.05.2006 18:07
zwei arrays vergleichen moose PHP Tipps 2006 1 06.04.2006 06:58
Arrays kreuzen PHP Tipps 2006 13 08.03.2006 11:36
[Erledigt] 2 Arrays miteinander vergleichen PHP Tipps 2007 3 17.12.2005 16:54
Objektorientierter Zugriff auf Multidimensionale Arrays PHP-Fortgeschrittene 31 26.11.2005 21:46
Problem beim vergleichen von 2 Arrays PHP Tipps 2005-2 1 06.10.2005 14:25
Arrays vergleichen PHP Tipps 2005-2 4 16.06.2005 15:41
2 Arrays vergleichen und unterschiede auslesen PHP Tipps 2005 6 25.02.2005 09:34
Erkennung von Arrays in Strings PHP-Fortgeschrittene 15 07.12.2004 13:00
zwei arrays miteinander vergleichen PHP Tipps 2004 6 01.09.2004 19:39
2 arrays in abhängigkeit ??? PHP Tipps 2004 2 11.08.2004 21:19

Besucher kamen über folgende Suchanfragen bei Google auf diese Seite
arrays vergleichen, datetime php überschneidungen, arrays vergleichen php, überschneidung vermeiden datetime mysql einfügen, php varrays vergleichen, daten array vergleichen php, php function verschiedene arrays vergleichen, php if array = array, php arrays überschneidungen löschen, php array überschneidungen, grosse arrays vergleichen, php array überschneidung, kollision arrays vergleichen, datenbankabfrage mit array vergleichen, php zwei arrays anzahl überschneidungen, große arrays vergleichen, grosse php array, php datenbankabfrage array, php datenbankabfrage mehrere nummern, php sehr große array

Alle Zeitangaben in WEZ +2. Es ist jetzt 20:06 Uhr.




Powered by vBulletin® Version 3.7.2 (Deutsch)
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
Aprilia-Forum, Aquaristik-Forum, Liebeskummer-Forum, Zierfisch-Forum, Geizkragen-Forum

Creative Commons License
Dieser Inhalt ist unter einer Creative Commons-Lizenz lizenziert.