[ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ]

Session D-CPER

Performance Optimierung von VFP Client/Server Anwendungen

Arturo Devigus
Devigus Engineering


Zusammenfassung

Client/Server Entwicklungen drängen sich nicht nur wegen Performance Überlegungen auf. Dennoch spielt in der heutigen IT Landschaft die Performance einer Client/Server Lösung eine entscheidende Rolle. Performance wird hierbei als Gradmesser für die Geschwindigkeit verstanden, mit welcher der Benutzer einer Software seine Arbeit erledigen kann. Es wird aufgezeigt, welche allgemeinen Fehler bei der Client/Server Entwicklung vermieden werden müssen, um eine gute Performance zu erzielen. Am Beispiel des Client/Server Frameworks Visual Extend wird aufgezeigt, dass selbst bei Verwendung von mehreren Views für ein und dasselbe Form, nicht alle Views in der Datenumgebung des Forms geöffnet werden müssen. Auch wird darauf hingewiesen, wie für Auswahllisten und Comboboxen resourcenschonend gearbeitet werden kann, um die Gesamtperformance zu verbessern. Diese Session ergänzt die anderen beiden Client/Server Sessions.

Voraussetzungen

Sie haben bereits erste Client/Server Anwendungen entwickelt oder haben dies in der nächsten Zeit vor. Sie wollen sich einen Überblick über Performance relevante Aspekte in der Client/Server Entwicklung verschaffen, welche Sie in Ihren eigenen Projekten sofort umsetzen möchten. Es wird vorausgesetzt, dass der Teilnehmer weiss, was eine Remote View ist, und dass in einer 2-Tier Client/Server Anwendung der Client immer mit einer Connection auf den Datenbank Server zugreift.

Connections

Um es gleich vorweg zu nehmen. Ein sehr grosses Optimierungspotential liegt darin, seine Client/Server Anwendung bzgl. der Verwendung von Connections zum Datenbankserver, zu optimieren. Ein allzu sorgloses Verwenden von Connections kann sich bitter rächen.

Es drängt sich hierbei der Ansatz auf, dass man im Wesentlichen pro Benutzer und Applikation nur eine einzige Connection vom Client auf den Datenbankserver zulässt. Nur dann, wenn es wirklch nicht anders geht, dürfen zusätzliche Connections erstellt werden.

Wenn man sorglos mit Remote Views und manuell erstellten Connections für SPT Anweisungen umgeht, ist es mit der Performance früher oder später nicht weit her. Man stelle sich einmal vor, wieviele Connections geöffnet werden, wenn man ein Form lädt, das bereits in der Datenumgebung eine Reihe von Remote Views besitzt und zusätzlich noch eine nicht zu unterschätzende Anzahl Comboboxen oder Listboxen, alle natürlich wieder mit eigenen Remote Views als Row Sources und folglich wieder Connections. Es wird relativ schnell klar, das das sicher nicht die resourcenschonendste Art und Weise der Client/Server Programmierung darstellt.

Neben der Performance sind bei der Verwendung von Connections vom Client zum Server natürlich auch lizenzrechtliche Aspekte zu berücksichtigen.

Die Connection Definition im DBC

Wird eine Remote View erstellt, so muss man zunächst eine Connection aus dem DBC auswählen. Doch Achtung: Diese "DBC Connection" ist nur die Definition, wie auf den SQL Server zugegriffen werden muss und hat mit den effektiven Connections, welche später durch das Öffnen von verschiedenen Remote Views verwendet werden, nichts zu tun. Die Connection Definition wird im VFP Database Container (DBC) abgespeichert.

Die im DBC zu definierende Connection beinhaltet folgende Informationen:

Um zur Laufzeit die Connection den aktuellen Bedingungen beim Kunden am besten anpassen zu können, empfiehlt es sich, mit der Option "Connection string" zu arbeiten. Ein ausführlicher Connection String beinhaltet folgendes:

DSN=Fibu;SERVER=(local);UID=;APP=Microsoft® Visual FoxPro®;WSID=HINOTE2000;DATABASE=Fibu;AutoTranslate
=No;Trusted_Connection=Yes;UseProcForPrepare=0;QuotedId
=No;AnsiNPW=No

Wobei die einzelnen Optionen im Wesentlichen denjenigen Einstellungen entsprechen, welche auch beim Definieren eines ODBC-DSN Eintrages vorkommen.

TIP:Um obigen Connection String zu erhalten, kann man auf "Verify Connection" klicken. Es wird hierbei alles aus der entsprechenden DSN Definition gelesen und entsprechend in den Connection String aufgenommen.

WICHTIG: Um beim Einsatz Ihres Programmes beim Kunden keine Probleme zu haben, müssen Sie unbedingt sicherstellen, dass keine umgebungsspezifischen Einstellungen im Connection String vorkommen. Am sichersten ist es, wenn Sie hierzu nur den DSN=DsnName Eintrag, wie in obigem Bild dargestellt, verwenden. Das gibt Ihnen die Möglichkeit, beim Kunden vor Ort die Einstellungen in der DSN Definition, d.h. beim Definieren der ODBC Verbindung, vorzunehmen. Um zur Laufzeit den Connection String zu manipulieren, z.B. weil der Kunde mit einem anderen DSN Eintrag arbeiten muss, oder diesen zur Laufzeit ändern will, bietet VFP folgende Möglichkeit:

dbsetprop("conFibu", "CONNECTION", "ConnectString", "dsn=" + alltrim(m.gs_dsn))

 Das ist sehr praktisch und bietet sich an, um System- oder manchmal sogar Benutzerspezifische Einstellungen zur Laufzeit entsprechend anzupassen.

Denken Sie aber immer daran, wenn Sie z.B. systemspezifische Einstellungen zur Laufzeit einstellbar machen, dass Sie diese dann auf ALLEN Arbeitsstationen entsprechend sicherstellen müssen. So muss z.B. ein definierter DSN Eintrag unbedingt bei allen Benutzern vorhanden sein. Das ist mitunter einer der Hauptgründe, weshalb sich eine 3-Tier Architektur gegenüber einer 2-Tier Architektur immer mehr durchsetzt. Bei einer 3-Tier Architektur gibt es nur einen Ort, wo Datenbankverbindungen hergestellt werden, diese werden nicht mehr von allen Clients aus vorgenommen. Das vereinfacht natürlich die Administration dbzgl. wesentlich und erhöht auch die Betriebssicherheit entsprechend.

Connections von Remote Views

Beim Erstellen einer Remote View muss immer zuerst eine im DBC vorhandene Connection ausgewählt werden.

Wird die Remote View anschliessend erstellt, ist in der View Definition die in obigem Dialog ausgewählte Connection Definition fest abgespeichert. Wird die Remote View erstellt, muss im Menu "Query"

die Option "Advanced Options…" angewählt werden, um folgende Einstellungen im "Advanced Options" Dialog vornehmen zu können:

Die Checkbox "Share Connection" ist mitunter eine der wichtigsten überhaupt. Nur wenn diese angeklickt ist, kann sichergestellt werden, dass eine neu geöffnete Remote View versucht, eine bereits vorhandene Connection einer zuvor durch eine andere Remote View geöffnete Connection, zu nutzen.

ACHTUNG: Eine manuell zuvor geöffnete Connection wird nie hierfür in Betracht gezogen! Das ist auch gut so, denn VFP kann ja nicht wissen, was mit dieser "fremden" Connection alles bewerkstelligt wurde oder noch wird. Vielleicht wurde damit ja bereits ein SQL Prepare String an den Server gesendet oder es läuft bereits eine Transaktion darauf.

Was VFP aber kann, ist das Verwenden einer Connection, welche VFP selbst für das Erstellen einer anderen Remote View bereits eröffnet hat. Das und nur das bedeutet "Share Connection".

Daraus ergibt sich folgende Schlussfolgerung, um bei deiner Anwendung bzgl. der verwendeten Connections zum Datenbankserver eine möglichst hohe Performance zu erziehlen:

Perfomance Richtlinien im Zusammenhang mit Connections

Es ergeben sich folgende Performance Richtlinien, welche im Zusammenhang mit offenen Connections vom Client zum Datenbank Server stehen:

  • Für jeden Benutzer und Anwendung ist eine Remote View zu öffnen, welche am besten gleich nach dem Start der Applikation geöffnet wird, und während der gesamten Laufzeit der Applikation nicht mehr geschlossen wird. Alle Remote Views, verwenden die Option "Share Connection", wie oben beschrieben und verwenden somit ein und dieselbe Connection. Dies auch über verschiedene Forms mit "private datasession".
  • Es werden für alle SPT Anweisungen maximal eine separate Connection verwendet. Evtl. kann sogar dieslbe "shared" Connection, welche bereits für die Remote Views verwendet wird, eingesetzt werden. Um diese zu ermitteln, kann mit der Anweisung lnconnection = CURSORGETPROP("ConnectHandle") die Connection Nummer ermittelt werden. (Diese sollte 1 sein, wenn die Connection ganz zu Beginn durch das Öffnen einer ersten Remote View erstellt wurde).
  • Es muss für jede SQL Prepare Query eine zusätzliche Connection verwendet werden. Sendet man SQL Prepare Strings an den SQL Server, so muss hierfür die Connction exklusiv verwendet werden! In diesem Fall gibt es keine andere Möglichkeit, als eine neue Connection zu verwenden. SQL Prepares lohnen sich demzufolge wirklich nur, wenn sehr häufig hintereinander dieselbe Anweisung abgesetzt wird.

Aus diesen Richtlinien ergibt sich, dass man sich bei den Remote Views eigentlich keine besonderen Gedanken mehr zu machen braucht. Oder doch? Da wäre noch dieses eine kleine Detail…

Busy Connections

Eine Connection kann auch einmal "busy" (also beschäftigt) sein! Dem muss natürlich vorgebeugt werden, ansonsten der Ansatz, eine einzige Connection für alle Remote Views zu verwenden, natürlich zum Scheitern verurteilt ist. Deshalb ist darauf zu achten, wie man bei den oben gezeigten "Advanced Options" der Remote View Definition die Einstellungen "Numer of Record to Fetch at a time", sowie "Maximum number of records to fetch" auf -1, d.h. alle, einstellt. Macht man nämlich den Fehler, und sagt, es sollen nur die ersten 100 Datensätze bezogen werden, die abgesetzte Query jedoch z.B. 101 Datensätze beinhalten würde, so würde die Connection "busy" bleiben, bis der 101ste Datensatz wirklich bezogen wird! Dieser Zustand ist alles andere als wünschenswert und führt auch noch zu anderen unangenehmen Situationen. So ist es z.B. auch nicht möglich, im Falle einer solchen "busy" Connection einen Datensatz in der View upzudaten oder einen neuen Datensatz über die View in der Server Datenbank anzulegen.

Man tut sehr gut daran, "busy" Connections gar nicht erst entstehen zu lassen. Sind Operationen asynchron durchzuführen, bietet sich sowieso eher der Ansatz über ADO und spezielle WITH EVENTS in VB bzw. der VFPCOM.DLL an.

Der VFX Connection Manager

Um diejenigen Connections, welche man bzgl. SPT und prepared SQL Queries manuell verwalten will oder muss, wäre es natürlich sehr nützlich, hätte man einen Connection Manager, der einem folgende Dinge abnehmen würde:

  • Erstellen einer neuen Connection
  • Holen einer freien Connection und nur falls nötig eine neue Connection erstellen
  • Übersicht über alle Connections in eigenem Connection Pool
  • Schliessen aller mit dem Manager erstellten Connections
  • Setzen und Lesen der Connection Parameter wie DBC Connaction name, DSN Name, User ID und Passwort
  • Eigene Garbage Collection mit Schliessen aller Connections bei Destroy des Objektes

Sie ahnen es natürlich bereits: VFX besitzt einen solchen Connection Manager und ich werde diese nützliche Klasse und deren Verwendung in der Session kurz vorstellen.

Remote Views vs. SPT

Wenn man eine Remote View definiert und mit "Share connection" darauf achtet, dass man nicht neue Connections verwendet, hat man eigentlich schon einen grossen Schritt in Richtung Performance Optimierung getan. Will man nun auch noch die letzten 10% Peformance Gewinn rausholen, kann es sich sogar lohnen, dass man zur Laufzeit aus den Remote Views SPT Anweisungen macht, da diese i.d.R. noch einen Tick schneller laufen, als die entsprechenden Remote Views.

Comboboxen und Pickfields, (u.U. sogar noch Grids), sind dbzgl. besonders dankbare Optimierungs Kandidaten.

In VFX haben wir dbzgl. die Möglichkeit geschaffen, bei Comboboxen, Pickfields und Grids statt die zur Designzeit definierten Remote Views, diese zur Laufzeit vollautomatisch in SPT Anweisungen "umzubauen" und so von der etwas rascheren Verarbeitungsgeschwindigkeit von SPT Anweisungen zu profitieren.

Es genügt hierbei im Wesentlichen, die entsprechende Property, namens lUseSPT auf .t. zu setzen. VFX nimmt dann intern den oben beschriebenen Connection Manager zu Hilfe, um eine freie Connection zu verwenden, um die SPT Anweisung erfolgreich absetzen zu können.

Erstellen von SPT Anweisungen aus Remote Views

Das VFX Framework erstellt aus den Remote View Definitionen die entsprechenden SPT Anweisungen, indem die Remote View gelesen wird und als SPT String abgesetzt wird.

[ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ]