Multidimensionales Array Performance probleme

un1x86

Grünschnabel
Hallo zusammen,

Ich habe folgendes Problem. Ich lese daten über meine orakel db Funktion aus einer Orakel Datenbank aus und bereitdie diese Daten auf. Diese Funktion liefert mir 1 Array mit folgenden Daten zurück

PHP:
array ( 'rows' => anzahl einträge, 'row' => array (DB daten) )

die DB Daten sehen ca. so aus

PHP:
array ( [0] => array(
                             [0] => value, 
                             [1] => value,
                             [140] => value), .... 
           [900] => array(
                             [0] => value, 
                             [1] => value .... 
                             [140] => value)
        )

Was ich damit sagen will ist, dass das Array ca. 900 Einträge hat und jeder dieser Einträge hat nochmals 140 Einträge drin.

Dieses Array zu bauen (Auslesen der Datenbank und die Aufbereitung) dauert ca. 0.93 Sekunden. Jedoch dann das Auslesen und anzeigen über ein normales foreach gibt mir einen timeout oder ist seeehr langsam

So lese ich das Array aus:

PHP:
$reportQuery = query($sql);
// List content
                        $content_blk = &$report_tpl->add_block('listcontent');
                        $count = 1;
                        foreach( $reportQuery['row'] as $row )
                        {
                                $td_blk = &$content_blk->add_block('listtd');
                                $content_blk->add_var('nr',$count);
                                $count++;
                                foreach ( $row as $td )
                                {
                                        if ( $td == '' )
                                        {
                                                $td_blk->add_var('name',' ');
                                        } else
                                        {
                                                $td_blk->add_var('name',$td);
                                        }
                                        $td_blk->next_block();
                                }
                                $content_blk->next_block();
                        }

und hier ist meine Orakle DB funktion "query"

PHP:
function query($query='')
{
        $return = array('result'=>false, 'row'=>array());
        $dbUser = 'username';
        $dbPass = 'password';

        $server = @oci_pconnect($dbUser,$dbPass);

        if ($server !== false)
        {
                        $result = @oci_parse($server,$query);

                        if ( !$result )
                        {
                                show_error(oci_error($server));
                        } else
                        {
                                $r = @oci_execute($result);

                                if ( !$r )
                                {
                                        // ERROR
                                        $err = oci_error($result);
                                        show_error($err);
                                }
                        }
        }
        else
        {
                $result = false;
                show_error(oci_error($server));
        }

        if ( oci_statement_type($result) == "SELECT" && is_resource($result) )
        {
                $return['result'] = true;

                while ( $row = oci_fetch_array($result,(OCI_ASSOC+OCI_RETURN_NULLS))  )
                {
                        $return['row'][] = $row;
                }

                $return['rows'] = count($return['row']);
        }
        return $return;
}

hat hier jemand eine Idee, wie ich das ganze schneller programmieren könnte?
 
EVA-Modell? :rolleyes:

900 x 140 macht insgesamt 126.000 Felder. Das ist erstmal ne ganze Menge, wenn man bedenkt, dass jedes (zumindest in PHP) mindestens ein Byte belegt. Das hört sich nicht viel an, haut aber auf spätere Sicht ziemlich rein (Schon allein fast eine Sekunde zum Fetchen der Daten ist recht enorm).
Ist es zwangsweise notwendig, alle Daten auszulesen? Wenn nicht, bietet sich eine Limit-Klausel an. Ist die Ausgabe wirklich dynamisch oder statisch, was zB die Feldbezeichnungen angeht? Letzteres würde dann die Möglichkeit mit sich bringen, die Ausgabemaske ein wenig zu stabilisieren und nicht noch in unnötige Schleifenkonstrukte und If-Else-Statements auszuarten. Wenn du zB weißt, dass jede Reihe dieser Abfrage drei Spalten zurückliefert, die immer "a", "b" und "c" sind, könnte eine Schleife reichen, mit der die Reihen, nicht aber gesondert die Spalten durchlaufen werden.

Warum es zu einem Timeout kommt, ist schwer zu sagen. Werden die Daten dann direkt ausgegeben, oder nochmal mit einer Buffer-Funktion zurückgehalten? Letzteres könnte zu einem Speicherüberlauf führen.
Eventuell hilft eine bessere Maschine auch ein wenig, obwohl das eher die letzte Alternative sein sollte. Hab mal kurz lokal 900 x 140 Mal geschachtelte for-Schleifen durchlaufen lassen, die nix machen. Alleine das dauerte fast 1.5 Sekunden. Was das für foreach und große Datenvorräte heißt, kannst du dir sicher denken.
Einen kleiner Performancetrick in foreach-Schleifen möchte ich dennoch gerne anmerken:
foreach($array as &$item) referenziert das gegenwärtige Feld anstatt eine Kopie in $item zu erstellen, was eventuell einen kleinen Performanceschub bringen könnte.
 
Hi

Danke für die Antworten. Direkt ausgeben? Ich wollte vermeiden, dass ich überall wieder die ganzen Orakel Funktionen anwenden muss. Auf diese Weise kann ich diese Funktion ersetzen durch eine mysql funktion und könnte somit auch der DB typ wechseln. Oder gibt es da noch andere akzeptable Lösungen?

maeTimmae

Was ist ein EVA Modell? In diesem Fall kann ich die Daten nicht kürzen. Das ist "worst" case wenn jemand alles angezeigt haben will.
 
Eingabe-Verarbeitung-Ausgabe. Klar kann man alles sofort ausgeben, aber spätestens dann, wenn man nachträglich entscheiden muss, ob zB noch ein Header gesetzt, oder ein anderer Inhalt ausgegeben werden muss, steht man vor der Aufgabe, doch alles nach einem schrittweisen System (und da bietet sich EVA an) aufzubauen.
Dieser Kommentar bezog sich jedoch eher auf mr_e.

Nun ja, hier sollte entschieden werden, ob es nicht eventuell sinnvoller wäre, dem Kunden eine seitenweise Ansicht zu gestatten. Je nach Situation und Voraussetzungen sind 10 bis 100 Ergebnisse pro Seite angemessen, alles andere erachte ich im normalen Anwendungsbereich als überfordernd, auch für den Betrachter.
Eine Blättern-Funktion könnte das Betrachten der Datensätze erleichtern und die Performance steigern.

Wenn es immer noch nicht anders geht, würde ich die Ablage der Datensätze in eine statische Datei organisieren, wie zB eine XML-Datei. Diese könnte dann einmalig erzeugt und regelmäßig aktualisiert als entlastende Instanz geschalten werden (Im Falle der Wahl, dass alle Datensätze angezeigt werden sollen). Nichtsdestotrotz würde ich eine weniger lastige Variante präferieren, wie die Limitierung, da es sowohl den Server als auch den Rezipienten entlastet. Was wird wohl sein, wenn da noch ein paar 100 Datensätze dazukommen? ;)
 
Hi

Leider brauche ich den ganzen Datensatz, da ich es ebenfalls ins Excell exportieren muss als ganze liste.

Das ganze in "cache" files abzulegen würde wenig Sinn machen. Aus folgenden Gründen. Es ist ein Report tool. Das ganze basiert auf den Eingaben des Kunden. Solange er wirklich alles anzeigen will ist das ja noch möglich wobei die Daten dynamisch bleiben sollten. Aber sobald der Kunde alles angezeigt haben will, jedoch gewisse Informationen exkludiert kann ich das cache file bereits nicht mehr brauchen.

Habe mir gerade was überlegt. Ich kann ja trozdem das ganze Array laden, das geht ja relativ schnell. Jedoch wie du bereits sagst einfach bei der Anzeige eine Seitenansicht einbauen. Somit könnte ich das ganze Array immernoch für den excell export brauchen, welches ja sehr gut funktioniert.
 
Die Frage, die sich mir stellt ist, ob der Server oder PHP schlappmacht, oder es gar nur eine temporäre Leistungssache war, dass ein TimeOut angenommen wurde?

Im Falle der Serversoftware sollte eventuell einfach die Request-Laufzeit heraufgesetzt werden, im Falle von PHP könnte man mit zB via [phpf]set_time_limit[/phpf] die maximale Laufzeit auf "0" setzen, also unendlich lange. Bereits verwertete Daten könnte man dann verwerfen und somit Speicherplatz freigeben (was in PHP leider nicht so einfach und effektiv während der Laufzeit möglich ist).

Grundsätzlich hilft gegen langsam laufende Scripte eine Optimierung des Codes. Dazu zählt, das statisch zu machen, was statisch geht und das, was dynamisch eingebunden werden soll, möglichst trivial einzufügen. Wenn du 900 * 140 * x Funktionen, Klauseln und so weiter aufrufst oder auswertest, produziert das einen gewaltigen Overhead, der eventuell gar nicht nötig ist.
Mit Oracle habe ich bisher noch keine wirklichen Erfahrungen sammeln können, aber eventuell lassen sich bestimmte Datensätze bereits im Query formatieren und modifizieren? Die meisten Datenbankmaschinen arbeiten für ihre Zwecke schneller als es eine höhere Sprache kann (Ausnahmen bestätigen die Regel).
 
Die Maschine ist eine Sun Fire T2000 8 Core mit 64 GB Memory. Mir ist noch etwas anders eingefallen. Ich könnte gewisse Prozesse gleich über einen system() Befehl im Hintergrund laufen lassen welches mir die HTML page generiert und ich dan mit PHP diese anzeige.

Ich habe den SQL query getestet auf dem Orakel Server direkt. Die Daten kommen sehr schnell. PHP braucht einfach aus meiner Sicht eine Weile bis es die Verbindung erstellt hat. Dies ist aber bei mir nur beim ersten aufruf, da ich die Verbindung über pconnect mache. Das Problem liegt wirklich nur am parsen des arrays. Auch nur das Anzeigen mit einem print_r($array) rattert der Webbrowser ganz schön. Aber es gibt auf jedenfall keinen timeout.
 
Dass ein Oracle Benutzer keine sanfte Maschine benutzt, hätte mir klar sein sollen - Um die Hardware kannst du dich von meiner Seite aus beneidet fühlen :-)

An sich ist PHP recht schnell, was das verarbeiten und rendern angeht - Ist ja nicht umsonst Scripthochsprache Nummer 1, wenn es um *netapplikationen geht. Eventuell ist es aber in der Tat so, dass PHP mit den 126 Tausend Feldern leicht überfordert ist, oder andere Algorithmen einfach zu sehr bremsen / einen hohen Overhead erzeugen.

Ich würde abraten, die Ausgabe über ein system callback abzusetzen, da das Aufgreifen eines Streams und das Auswerten über zB system() höchstwahrscheinlich noch höhere Performanceeinbußen nach sich zieht.
Eventuell ist eine Transkription des Ausgabescripts in eine andere (precompilierte?) Hochsprache sinnvoll, wie zB Java oder C++. Eine Java-Maschine mag eventuell ein wenig langsamer von Beginn an sein, das jedoch dürfte die eingesetzte Rechentechnik maximal kitzeln, nicht aber ins Schwitzen bringen. Den reellen Vorteil aber kann ich leider nicht abschätzen, aber bei solchen kritischen Anwendungen würde ich dennoch empfehlen, eine Umsetzung in Java (o.a.) zu wagen und zu testen.
 
Zurück