frontenduser speedup

Fragen zur Installation von CONTENIDO 4.9? Probleme bei der Konfiguration? Hinweise oder Fragen zur Entwicklung des Systemes oder zur Sicherheit?
Antworten
emergence
Beiträge: 10653
Registriert: Mo 28. Jul 2003, 12:49
Wohnort: Austria
Kontaktdaten:

frontenduser speedup

Beitrag von emergence »

ich hab mir den code jetzt wirklich mal genau durchgesehen und bin natürlich auf das problem genagelt das bei vielen plugins und sagen wir mal 100 frontenduser die preformance sowas von in den keller geht, das man dazwischen ne zigarette rauchen kann...

leider ist es so, dass man es in der jetzigen konstellation nicht wirklich beschleunigen kann, ohne ein neues feature bei den einzelnen plugins einzuführen...

in den plugins selbst gibts ja einige funktionen wie zb

bsp:

Code: Alles auswählen

function frontendusers_name_wantedVariables ()
{
	return (array("name"));
}

function frontendusers_name_canonicalVariables ()
{
	return array("name" => i18n("Name", "frontendusers_name"));
}

function frontendusers_name_getvalue ($field)
{
	global $feuser;

	if ($field == "name")
	{
		return $feuser->getProperty("address", "name");
	}
}

function frontendusers_name_store ($variables)
{
	global $feuser;

	if (!array_key_exists("name",$variables))
	{
		return false;
	} else {
		$feuser->setProperty("address", "name", $variables["name"]);
		return true;
	}
}
der ansatz punkt den ich vorschlagen würde -> entweder ne neue funktion hinzufügen/oder ne bestehende ausbauen die für jedes feld,
in dem fall : name

die property definition also aus der con_properties:
type: address
name: name

retour liefert...

wie gesagt, dieses feature gibts in dem sinne noch nicht...
jedoch könnte man es dann dazu nutzen um !ein! sql query zu generieren, welches dann exakt die FrontendMembers retour liefert...

probleme die dabei auftreten können/werden:
eventuell wären diese plugins nicht mehr zu den alten kompatibel...
die class.genericdb.php müsste vielleicht auch dafür modifiziert werden...

vorschläge/unterstützung ist willkommen...
*** make your own tools (wishlist :: thx)
HerrB
Beiträge: 6935
Registriert: Do 22. Mai 2003, 12:44
Wohnort: Berlin
Kontaktdaten:

Beitrag von HerrB »

Na ja, ich hatte dazu ja mal eine Idee beigesteuert. Auf den Edit-Seiten macht das Konstrukt IMHO relativ wenige Probleme (da nur für einen User/Datensatz die Plugins durchgegangen werden müssen).

Probleme sehe ich bei:
1. Auflistungen/Übersichten
2. Sortierung
3. Suche

Mein Vorschlag war, in der class.genericdb.php eine Methode getPropertyAll zu definieren, die pro Element alle Properties einliest und in ein Property-Array (des Objekts) überträgt [sowas wie $aProperty[$type][$name] = $value]). Das ist einfach, da die Properties durch Name der Item-Klasse und ID relativ eindeutig definiert sind.

Nun würde ich getProperty ändern (sinngemäß):
"Wenn Type+Name Element in aProperty, dann return $aProperty[$type][$name], sonst hole Daten aus DB"

Hierbei ergibt sich natürlich das Problem, dass es noch in die DB geht, wenn ein Wert bisher noch nie geschrieben wurde. Da gäbe es entweder die Möglichkeit, eine spezielle getPropertyFromArray Methode zu ergänzen oder in getPropertyAll ein Flag zu setzen, welches in getProperty abgefragt wird (vermutlich die eleganteste Methode). D.h. wenn "bArrayAvailable", dann liefere nur die Information aus dem Array.

Das löst 1. und ergibt eine Abfrage pro Element, halte ich für vertretbar.

2. und 3. können auf diese Weise verbessert werden.

Das schöne an der Lösung ist, dass weder an den Plugins noch in den Dialogfenstern zunächst etwas geändert werden muss - jedoch z.B. das FrontendUser-Menü recht einfach signifikant beschleunigt werden könnte.

Leider ist auch dieser Ansatz IMHO nicht geeignet, 2. und 3. zu lösen (deswegen auch nur "verbessern"), da nach wie vor alle Daten zunächst eingelesen, im Speicher gesucht und die Ergebnisse sortiert werden müssen. Bei 2000 Usern und 20 Plugins mit 20 Feldern reduziert sich aber immerhin die Abfragezahl von 1 + (2000 x 20) = 40001 auf 1 + 2000 = 2001.

Eine echte, hochperformante Lösung für das Problem (wenn auch in Plugin-Informationen gesucht und nach ihnen sortiert werden soll) gibt es IMHO nur, wenn man
a) die Speicherung von Plugin-Informationen auf die Properties-DB der gleichen Datenbank einschränkt und
b) die Plugins geeignet erweitert, so dass eine SQL-Abfrage konstruiert werden kann, die das gewünschte Ergebnis liefert

Es könnte evtl. auch Sinn machen, wie von Dir vorgeschlagen, in den Plugins eine Methode zu ergänzen, die Typ und Name der verwendeten Properties als Array zurückliefert. Allerdings nützt das nur etwas, wenn die späteren Daten aus den Properties geliefert werden (Argument von timo: Die Daten der Plugins könnten auch aus einer Text-Datei oder einem Webservice geliefert werden).

Bei der aktuellen Überarbeitung des Newsletter-Bereichs (gleiches Problem) habe ich es zunächst so gelöst, dass ich wieder zurück zu den Basic gegangen bin: Es wird ein SQL-Statement mit LIMIT erzeugt, Plugins werden (noch) nicht berücksichtigt (in der Auflistung).

Ist wahnwitzig schnell... :wink:

Gruß
HerrB
Bitte keine unaufgeforderten PMs oder E-Mails -> use da Forum!

Newsletter: V4.4.x | V4.6.0-15 (Module, Backend) | V4.6.22+
Standardartikelliste: V4.4.x | V4.6.x
http://www.contenido.org/forum/search.php | http://faq.contenido.org | http://www.communido.net
emergence
Beiträge: 10653
Registriert: Mo 28. Jul 2003, 12:49
Wohnort: Austria
Kontaktdaten:

Beitrag von emergence »

HerrB hat geschrieben:Allerdings nützt das nur etwas, wenn die späteren Daten aus den Properties geliefert werden (Argument von timo: Die Daten der Plugins könnten auch aus einer Text-Datei oder einem Webservice geliefert werden).
tja an die möglichkeit hab ich vorerst noch gar nicht gedacht...
ist ein argument... bremst jedoch das ganze aber nochmals um den faktor 10 aus...

die idee alle properties eines items abzufragen ist ne möglichkeit, aber nicht eindeutig... man kann auf grund der daten die dann geliefert werden, nicht schließen welche properties wirklich zu dem plugin gehören...

aber zurück zu den externen datenquellen...
sagen wir mal wir möchten den teil auch noch mit bedienen...
dann müsste das plugin selbst die info liefern wie zu verfahren ist... (super komplizierte sache das)

ich könnte mir vorstelle die

frontendusers_".$plugin."_canonicalVariables so zu modifizieren das sie für jedes feld einen erweiterten array retour liefert...

momentan liefert er ja nur
['feldname'] => 'i18ntranslation'

praktische würde ich finden wenn
['feldname'] => Array ( 'trans' => 'i18ntranslation',
'type' => 'feldtyp',
'name' => 'feldname',
'handler' => 'plugin' )

wenn handler 'plugin' wäre würde
frontendusers_".$field."_getvalue verwendet werden...

gibts handler zb nicht würde die con_properties verwendet werden...

einen großteil könnte man dann wirklich über eine sql abfrage lösen...

so long, good nite..
*** make your own tools (wishlist :: thx)
HerrB
Beiträge: 6935
Registriert: Do 22. Mai 2003, 12:44
Wohnort: Berlin
Kontaktdaten:

Beitrag von HerrB »

Ja, das meinte ich. Persönlich habe ich mich (für den Newsletter-Bereich) auf das Argument zurückgezogen, dass man dann halt die Daten irgendwie aus der externen Quelle in die Properties-Tabelle überspielen muss.

Oder in eine andere Tabelle der DB, wobei dann das Plugin - wie von Dir vorgeschlagen - "seinen" Anteil zum SQL-Statement liefern muss.
die idee alle properties eines items abzufragen ist ne möglichkeit, aber nicht eindeutig... man kann auf grund der daten die dann geliefert werden, nicht schließen welche properties wirklich zu dem plugin gehören...
Ist auch IMHO nicht notwendig. Die Plugins (und ihre Funktionen) werden ja einmalig includiert. Nun kann durchaus pro Element und Plugin einmal die getValue-Funktion des Plugins ausgeführt werden - und diese "kennt" ihre Daten und liefert mit getProperty die Daten aus dem Array.

Sind zwar ein bis zwei zusätzliche Funktionsaufrufe (im Gegensatz zum Direktzugriff auf die Information), aber ich denke, dass wäre unter der Prämisse der Flexibilität akzeptabel (es kommt aber sicherlich mal auf einen Test an).

Kann ja heute mal was basteln, brauche es eh für das FrontendUser-Plugin-Paket.

Gruß
HerrB
Bitte keine unaufgeforderten PMs oder E-Mails -> use da Forum!

Newsletter: V4.4.x | V4.6.0-15 (Module, Backend) | V4.6.22+
Standardartikelliste: V4.4.x | V4.6.x
http://www.contenido.org/forum/search.php | http://faq.contenido.org | http://www.communido.net
HerrB
Beiträge: 6935
Registriert: Do 22. Mai 2003, 12:44
Wohnort: Berlin
Kontaktdaten:

Beitrag von HerrB »

class.genericdb.php:

Code: Alles auswählen

	/**
	 * loadAllProperties ()
	 * Load all properties in object array
	 * @param none
	 * @return none
	 */
	function loadAllProperties ()
	{
		global $client, $cfg;
		$this->_bPropertyArrayAvailable = true;
		$this->aProperty 		= array();

		/* Runtime on-demand allocation of the properties object */
		/* if (!is_object($this->properties))
		{
			$this->properties = new PropertyCollection;
		} */

		/* If this object wasn't loaded before, return false */
		if ($this->virgin == true)
		{
			$this->lasterror = "No item loaded";
			return false;
		}

		$sSQL  = "SELECT type, name, value FROM ".$cfg["tab"]["properties"]." WHERE idclient = '".$client;
		$sSQL .= "' AND itemtype = '".$this->primaryKey."' AND itemid = '".$this->get($this->primaryKey)."' ";
		$sSQL .= "ORDER BY type, name";

		$this->db->query($sSQL);

		while ($this->db->next_record()) {
			$this->aProperty[$this->db->f("type")][$this->db->f("name")] = $this->_outFilter($this->db->f("value"));
		}
		/* This code doesn't help...
		$this->properties->select("idclient = '".$client."' AND itemtype = '".$this->primaryKey."' AND itemid = '".$this->get($this->primaryKey)."'", "", "type, name");
		while ($item = $this->properties->next()) {
			$this->aProperty[$item->get("type")][$item->get("name")] = $item->get("value");
		} */
	}

	/**
	 * getProperty ($type, $name, $loadAll)
	 * Sets a custom property
	 * @param string $type  Specifies the type
	 * @param string $name  Specifies the name
	 * @param bool $bLoadAll  Load all properties on first load into array?
	 * @return boolean Value of the given property
	 */
	function getProperty($type, $name, $bLoadAll = true)
	{
		if ($this->_bPropertyArrayAvailable) {
			return $this->aProperty[$type][$name];
		} else if ($bLoadAll) {
			$this->loadAllProperties();
			return $this->aProperty[$type][$name];
		} else {
			/* Runtime on-demand allocation of the properties object */
			if (!is_object($this->properties))
			{
				$this->properties = new PropertyCollection;
			}
	
			/* If this object wasn't loaded before, return false */
			if ($this->virgin == true)
			{
				$this->lasterror = "No item loaded";
				return false;
			}

			/* Return the value */
			return ($this->properties->getValue($this->primaryKey, $this->get($this->primaryKey), $type, $name));
		}
	}
In der loadAllProperties sind noch ein paar Reste enthalten (für eigene Experimente ... :wink: ).

Die Verwendung des Properties-Objekts war eine dusselige Idee - das verursacht natürlich genauso viel Datenbanklast.

Das ist übrigens alles, was nötig ist - die Funktion ist selbstaktivierend (z.Z.). Müsste man sich überlegen, ob das so sinnvoll ist...

Der Code reduziert die Ausführungszeit in Administration -> Frontend für 28 Frontend User bei 15 Plugins von ca. 3,2 Sekunden auf 1,2 bis 1,5 Sekunden... wobei ich zusätzlich eine bessere Skalierung erwarte ... :lol:

Verbesserungsvorschläge herzlich willkommen.

Gruß
HerrB
Bitte keine unaufgeforderten PMs oder E-Mails -> use da Forum!

Newsletter: V4.4.x | V4.6.0-15 (Module, Backend) | V4.6.22+
Standardartikelliste: V4.4.x | V4.6.x
http://www.contenido.org/forum/search.php | http://faq.contenido.org | http://www.communido.net
emergence
Beiträge: 10653
Registriert: Mo 28. Jul 2003, 12:49
Wohnort: Austria
Kontaktdaten:

Beitrag von emergence »

ich hab das jetzt mal ausprobiert...

mit einer etwas anderen version des cache (direkt in der class.properties.php)

getestet mit ca 150 frontenduser und 50 plugins pro user
ohne cache ca. 250 sekunden
mit cache ca. 160 sekunden

die anzahl der db queries ist um etliches zurückgegangen...
ohne cache 10345 queries...
auf
mit cache 7338 queries...

ergo um ein drittel schneller aber immer noch zu langsam...
d.h. mit nur cachen der properties springen wir nicht sonderlich weit...
*** make your own tools (wishlist :: thx)
HerrB
Beiträge: 6935
Registriert: Do 22. Mai 2003, 12:44
Wohnort: Berlin
Kontaktdaten:

Beitrag von HerrB »

Und, wie siehts aus? Wie sieht Deine Lösung aus? Bin doch so neugierig... :wink:

Gruß
HerrB
Bitte keine unaufgeforderten PMs oder E-Mails -> use da Forum!

Newsletter: V4.4.x | V4.6.0-15 (Module, Backend) | V4.6.22+
Standardartikelliste: V4.4.x | V4.6.x
http://www.contenido.org/forum/search.php | http://faq.contenido.org | http://www.communido.net
emergence
Beiträge: 10653
Registriert: Mo 28. Jul 2003, 12:49
Wohnort: Austria
Kontaktdaten:

Beitrag von emergence »

ähm, das ist momentan nur zu einem teil fertig...
ich hab jetzt nochmals das teil optimiert und bin ca auf 55 sekunden runtergekommen...

query anzahl liegt aber noch immer bei die 3300... zu viel

wenn ich wieder mehr zeit hab, werd ich das nochmal runterdrücken..
ich schätze ich werd bei 150 frontend user auf ca 170 sql abfragen kommen...

ich hab da in etwa bis jetzt 20 stunden reingesteckt und ob ich das veröffentliche wenn ich fertig bin weiss ich noch nicht...

momentan hab ich aber was anderes zu tun...
*** make your own tools (wishlist :: thx)
HerrB
Beiträge: 6935
Registriert: Do 22. Mai 2003, 12:44
Wohnort: Berlin
Kontaktdaten:

Beitrag von HerrB »

Ok, danke.

Gruß
HerrB
Bitte keine unaufgeforderten PMs oder E-Mails -> use da Forum!

Newsletter: V4.4.x | V4.6.0-15 (Module, Backend) | V4.6.22+
Standardartikelliste: V4.4.x | V4.6.x
http://www.contenido.org/forum/search.php | http://faq.contenido.org | http://www.communido.net
Antworten