Fallen beim Statuscheck lang laufender PHP-Jobs mit Ajax – III

Mit diesem Beitrag setze ich meine kleine Serie zu lang laufenden PHP-“RUN”s und asynchron gestarteten “CHECKER”-Programmen für Ajax-basierte Statusüberprüfungen des “RUN”s fort. Siehe:
Fallen beim Statuscheck lang laufender PHP-Jobs mit Ajax – I
Fallen beim Statuscheck lang laufender PHP-Jobs mit Ajax – II

Wir hatten bereits diskutiert, dass beide Jobs von ein und derselben Webseite über Ajax-Transaktionen zu starten und zu managen sind. Im besonderen ist das Status-Polling durch periodisches Starten eines “CHECKER”-Jobs zu erledigen. Das Starten erfolgt über eine periodische, jeweils nur kurze Zeit dauernde Ajax-Interaktion mit dem Server.

In beiden Fällen – beim einmaligen Start des RUNs und beim periodischen Start des CHECKERS – sind i.d.R. einige Daten zum Server zu übertragen. Diese Daten kann man z.B. in unsichtbaren Feldern eines Formulars hinterlegen und vor dem Ajax-Transfer serialisieren.

Im letzten Beitrag hatte ich bereits angedeutet, dass es im Zusammenhang mit der klaren Strukturierung der parallelen Ajax-Handhabung von mehreren Formularen folgende Vorgehensweisen sinnvoll sind:

  1. Jedes HTML Formular für einen per Ajax zu startenden Job wird auf der Javascript Seite vollständig auf ein zugehöriges, spezifisches Kontroll-Objekt “K” abgebildet. Definierte Methoden dieses Kontroll-Objektes übernehmen nicht nur die Serialisierung der asynchron zum Server zu transferierenden Daten, sondern kümmern sich auch um einen angemessene Reaktion auf Ajax-Rückmeldungen des Servers und übergeben bei Bedarf Teile der Server-Antwort an bestimmte HTML-Objekte (bzw. weitere zugehörige, abstrakte JS-Kontroll-Objekte).
  2. Um Submit-Events durch “K”-Methoden zu kontrollieren, ist die $.proxy – Funktion einzusetzen. Sie sorgt dafür, dass der “this”-Operator bei der Ersetzung der Submit-Funktionalität des HTML-Formulars (und seines Submit-Buttons) durch eine spezielle Submit-Methode (z.B. submit_event() ) des Kontroll-Objektes innerhalb dieser Methode weiterhin auf das Kontroll-Objekt zeigt – anstatt dem jQuery-Standard entsprechend auf das eventauslösende HTML-Element (also das Formular bzw. den dortigen Submit-Button).

Wir wollen diesen Punkt nachfolgend noch etwas vertiefen und anschließend beleuchten, wie sich der “this” Operator unter jQuery in den Methoden des Kontroll-Objektes zum Formular verhält. Wir berühren dabei zwar nur elementares jQuery/Ajax-Know-How, aber vielleicht ist das ja für den einen oder anderen interessant. Und es liefert die Basis für die Realisierung unseres RUN/CHECKER-Szenarios.

Einfacher Beispielcode für die Verwendung von $.proxy(), Ajax und this in einem Kontroll-Objekt zu einem Formular

Wir betrachten also ein Formular “F”, für das wir ein zugehöriges Kontroll-Objekt “K” definiert haben. Der Submit-Event des Formulars soll über eine Callback-Funktion “submit_event()” des “K”-Objektes abgewickelt und kontrolliert werden. Die spezielle Submit-Methode des Kontroll-Objekts ist über eine entsprechende “prototype”-Definition festzulegen. Also z.b. etwa so:

....
....
K = new Ctrl_k(); 	// in diesem Beispiel nur der Einfachheit halber eine globale Definition   

function Ctrl_K () {

	// Define and manage handles to other JS Control objects ...... 
	// Define and manage jQuery selectors for the form and its elements .....
	.......
	this.id_status_form = "# ...."; 
	.......
	.......
	
	// 
Register Events - e.g. replace the submit event of the form by a local method of the "K" object
	$(this.id_status_form).submit( 
		$.proxy(this, 'submit_event') 
	);
}

Ctrl_K.prototype.submit_event = function(e) {
		
	e.preventDefault();
	....
	....
	// Prepare Ajax transaction 	
	var url = $(this.id_status_form).attr('action'); 
	var form_data = $(this.id_status_form).serialize(); 
	var return_data_type = 'json'; 
	......
	$.ajaxSetup({
		contentType: "application/x-www-form-urlencoded; charset=ISO-8859-1",
		context:  this, 
		error: this.status_error, 
		.......
	});
	.....
	.....
	// Perform an Ajax transaction	
	$.post(url, form_data, this.status_response, return_data_type); 	
	.......		
	.......  				
};

Ctrl_K.prototype.status_response = function(status_result) {
	// Do something with the Ajax (Json) response 
	.....
	this.msg = status_result.msg;
	.....
};

Ctrl_K.prototype.status_error = function(jqxhr, error_type) {
	// Analyze the error  
	.....
	.....
};

“this” in der per $.proxy() adressierten Methode “submit_event” bezieht sich in diesem Beispiel auf das K-Objekt selber und nicht, wie es ansonsten unter jQuery der Fall wäre, auf das HTML-Objekt, das den Submit-Event ausgelöst hat (z.B. der Submit-Button des Formulars). Nur wegen $.proxy() können wir “this” in der gewählten Form überhaupt erfolgreich und in seiner angestammten Bedeutung in “submit_event()” verwenden.

Das bedeutet: Durch den konsequenten Einsatz von $.proxy ergibt sich die Möglichkeit innerhalb des JS-Codes systematisch und sehr weitgehend von Details der HTML-Oberfläche zu abstrahieren, ohne die intuitive Bedeutung für Objekt-Methoden unter JS/jQuery zu verletzen. Jeder HTML-Bereich (u.a. ein Formularbereich), der mit JS/jQuery zu behandeln ist, kann in Form eines

  • zugehörigen Kontroll-Objektes und
  • zugehöriger registrierter Methoden für die Events seiner HTML-Objekte

behandelt werden. Die notwendigen Kontroll-Objekte werden i.d.R. beim Laden der Web-Seite über Initialisierungsfunktionen erzeugt. Das ermöglicht einen sehr klaren Code-Aufbau – auch dann wenn man wie im RUN/CHECKER-Szenario für ein und dieselbe Webpage gleich mehrere Formulare und Ergebnisbereiche parallel und periodisch handhaben muss.

“this” und der Kontext der Ajax Success bzw. Error-Funktion

Wir wenden uns nun einem weiteren interessanten Punkt zu. Worauf verweist eigentlich “this” in der Ajax-Callback-Funktion “status_resonse” des “K”-Objektes ? Das ist ja die Funktion, die im Falle des Erfolges der Ajax-Transaktion aufgerufen werden soll.

In unserem Beispiel oben ist die Ajax Success-Funktion als Parameter der jQuery Convenience-Funktion $.post(..)” festgelegt worden. Hätte man nur $.ajax({ … }) zum Auslösen der Ajax-Transaktion verwendet, hätte man dort eine Callback-Funktion über
$.ajax({ …, success: this.status_response, … })
festgelegt. Etwas Analoges gilt natürlich für die Callback-Funktion zur Ajax-Fehlerbehandlung.

So ohne weiteres ist es leider überhaupt nicht klar, was “this” in einer Ajax-Success/Error-Callback-Funktion unter jQuery bedeutet oder bedeuten soll. Die Doku (http://api.jquery.com/jQuery.ajax/) sagt dazu:

By default, the context is an object that represents the ajax settings used in the call ($.ajaxSettings merged with the settings passed to $.ajax).

Na, wunderbar. Damit bezöge sich das “this” in unserer schönen Methode des “K”-Objekts also leider gar nicht auf das “K”-Objekt. Das diese Feststellung zutrifft, sollte der Leser selber testen. Siehe aber die Links unten.

Das
wollen wir aber nicht. Wenn wir eines klareren Programm-Designs halber schon ein abstraktes Kontroll-Objekt einführen, soll das “this” in seinen Methoden bitte schön auch immer auf das Kontroll-Objekt selbst verweisen – Ajax hin oder her. jQuery ist das aber zu Recht egal:

Bei etwas Nachdenken wird einem klar, dass der Kontext, auf den sich “this” im Ajax Success-Callbakc beziehen soll, sich auch nicht wirklich standardmäßig zuweisen lassen kann. Denn man hätte die Callback-Funktion ja auch direkt deklarieren können – nach dem Muster:

$.ajaxSetup({ 
	..., 
	success: function () {
		this.xxx = , ... 
	}, 
	.....
	.....
})      

Was soll “this” denn dann sein ??? Das hängt wohl von Bedarf und Design der Applikation ab. Die Antwort ist also:

Der Entwickler muss den Context für die Callback-Funktion explizit setzen. Er ergibt sich in sinnvoller Weise nicht von allein. Dazu verwendet man das Attribut “context” in demjenigen Objekt, das wir bei lokalen Ajax-Transaktionen der Funktion $.ajax() oder bei einer globalen Festlegung für alle Ajax -Transaktionen der Funktion $.ajaxSetup() übergeben.

Viele Entwickler weisen nun den Context des Success-Callbacks meist einem (hidden) HTML-Objekt zu. In unserem Ansatz mit einem abstrakten Kontroll-Objekt zum Formular tun wir das natürlich nicht! Wir weisen den Kontext vielmehr dem erzeugten Kontroll-Objekt “K” selbst zu. Sollte Output in anderen, von ihm nicht kontrollierten HTML-Objekte erzeugt werden müssen, können die notwendigen Daten aus der Ajax-Antwort ja immer noch in definierter Weise an andere Kontroll-Objekte weitergereicht werden.

Wenn das Objekt “K” global definiert ist, kann man also schreiben:

$.ajaxSetup({ 
	..., 
	context: K, 
	..... 
})     

Aufgrund des Einsatzes von $.proxy() geht es aber deutlich eleganter:

$.ajaxSetup({ 
	..., 
	context: this, 
	..... 
})     

So, nun haben wir gesehen, wie wir Formulare und zugehörige Ajax-Transaktionen mit $.proxy() und spezifischen Methoden von Kontroll-Objekten handhaben können. Im nächsten Beitrag dieser Serie

Fallen beim Statuscheck lang laufender PHP-Jobs mit Ajax – IV

befasse ich mich mit dem Timing des periodischen Aufrufs des CHECKER-Prozesses.

Links

http://stackoverflow.com/questions/3863536/how-to-pass-context-in-jquery-ajax-success-callback-function
http://stackoverflow.com/questions/6394812/this-inside-of-ajax-success-not-working
http://stackoverflow.com/questions/11027276/jquery-this-not-accessible-after-ajax-post

Eclipse Luna, SVN – problem with older Subversion 1.6 repositories !

In Eclipse I have to handle a variety of PHP projects (with additional natures) which are interconnected in different ways. E.g. my present project may for convenience have links to folders of another project in another Eclipse workspace. Such links exist in my case for example to files containing very basic classes of some of my own frameworks. In some projects I combine the present project work with upgrading the basic framework classes in parallel to a new level of capabilities. In such a situation I want to directly change the basic classes for all other projects that use them and test compatibility aspects.

The version control of almost all interconnected projects is done by Eclipse Subversive plug-ins from Polarion. The link situation on the folder/file side of my projects leads to so called external SVN relations on the SVN side of my interconnected projects. These relations are generated automatically by the Subversive plug-ins for Eclipse.

In some cases I may even have different SVN locations – some local, some on a dedicated SVN servers in the local network or on the Internet. Unfortunately, not all of my SVN repositories are of the same Subversion version – which was no problem as long as different connectors were available in Eclipse and the repositories were generated to be backward compatible. Some of my SVN repositories are relatively old ones – i.e. of SVN version 1.6. Mostly associated with framework classes I continuously have worked on for years.

From KDE’s SVN client “kdesvn” I am very familiar with the problem that e.g. a client for a Subversion version 1.8 is not able to deal with SVN repositories that were generated with an older version of Subversion (e.g. Subversion version 1.6). An error message including as “… working copy is too old …. “ is a typical indication of this situation. In this case it does not help that you may have set up the repository with backward compatibility (e.g. to SVN version below 1.6). You have to update your repository by using the command

svnadmin upgrade

inside the base directory of the repository. Which may be delicate – if you did not set up any backward compatibility your Eclipse plug-in may no longer be able to handle the repository.

So, before updating SVN in your Linux OS and upgrading your SVN repositories you should always check carefully, whether the Subversive SVN plug-ins in Eclipse will be able to handle the repository afterwards. Actually, already this type of problem indicates that a strategy to maintain SVN repository versions consistently should be followed. However, I am a bit lazy. And as long everything worked smoothly I had no reason to upgrade my SVN repositories to one and the same Subversion version.

Some days ago – due to some irritating errors of syntax highlighting in the Kepler JSDT module – I installed Eclipse LUNA (i.e. version 4.4.2.) instead of KEPLER. The JSDT highlighting error went away. However, I ran into deep trouble with the subversion plug-ins.

Actually, my Eclipse upgrade lead to a complete mess because of my laziness in the past to keep the different Subversion versions of SVN repositories on the same level. The following discussion may help others to recover from such a situation and reconsider a strategy to keep the Subversion versions of one’s SVN repositories consistently aligned.

Eclipse Subversive plug-ins for LUNA provide SVN Connector Kits for Subversion versions 1.7 and 1.8, only

Recently, I had started with a new PHP project in Eclipse KEPLER depending on a set of classes of one of my frameworks. So, I thought this project would be a good choice to get some experience with Luna. Without much thinking I had installed several Eclipse plugins I typically use into LUNA as PDT, WST, Mylyn, JSDT
Jquery , etc. and of course Subversion and Polarion Subversive SVN Connector Kits. So, I felt well prepared to open the my Kepler workspace with Luna.

The first thing you may stumble across when using Luna first time is that you should make a copy of your original PHP projects in the Kepler workspace directory. Luna will upgrade your Kepler project in a way that is not backward compatible to older Eclipse versions. Ok, that done, I wanted to share my upgraded project by using a SVN repository. I chose an existing local SVN location – based on the “file” sub protocol of SVN. Then I started to check in the directories and files of my project. The check in process seemed to work well in the beginning. But then I was bombarded with error messages. Besides other things the messages told me that subversion stumbled across an “unsupported working copy”.

Ok, I checked the installed connector versions of the SVN Polarion plug-ins and did additional research on the Internet – the connectors were for Subversion version 1.7 and 1.8, only! Others are not available for Luna! As I did not remember exactly the version of my local repository (probably 1.6) I disconnected the PHP project from SVN with allowing to delete all SVN information from disk.

Making a new repository for your present project may not help

Next thought: Well, lets make a new SVN repository then – of SVN version 1.8. I combined this step with setting up a local lightweight SVN server – because somebody had told me that the performance of the core SVN protocol would be much better than the “file” protocol. After the intermezzo of the server setup I manually created a new SVN database on my local SVN server (i.e. my workstation). As Subversion on the Linux workstation is of version 1.8 -I had no doubts that LUNA now should be able to work together with this SVN database. From Eclipse I shared my previously disconnected project by using the new SVN location with the generic “svn//” protocol. And started to check in again. Which started well and then ran into errors again … 🙁

To analyze what happened I set up a fresh independent project and filled it with some directories and files and tested SVN transactions with my version 1.8 SV repository. That worked perfectly! So, something obviously was wrong with my other more complicated project. A closer analysis showed what the reader may already have guessed:

The errors occurred during the check in process when directories were reached that were linked to my basic long term projects with their old repositories. Which on the SVN side are located in an “external” repository. So, my conclusion was:

One must first remedy the outdated working copy situation for the basic projects which your present project may depend on by links. Their (external) SVN repositories have to be upgraded first.

In complicated dependency situations you may run into more problems

Although the above conclusion is correct it may not directly lead to success. By walking through my projects and trying to get them working again with SVN under LUNA I stumbled across several situations which stressed my nerves. Among others there are 2 stupid things that may lead you to dead end situations and prevent a recovery from them with the Eclipse subversion tools:

  • After a trial to check in files into (too old) repositories there may be open outgoing SVN transactions left which cannot be resolved due to the impossibility to handle old SVN working copies of connected projects with linked folders. You are forced to completely disconnect your present project from the SVN repository with a deletion of all SVN information from disk (i.e. “.svn” files in the folders and sub folders of your Eclipse project)
  • In complicated link situations you may find the following: There may be a mixture of “.svn” files in a project which describe the diverse repositories of linked folders of other projects on different version levels. I found that with the present plug-ins of LUNA this may lead to unrevoverable SVN situations and even repository corruption.
  • Despite disconnecting projects and allowing for a deletion of SVN information some “.svn” files may remain at unexpected locations. This may depend of what kind of SVN trouble and corruption you had and what you tried to remedy the situation. The remaining “.svn” files may include old SVN version information – leading to trouble again when you try to connect to an SVN repository next time.

Eventually, I gave up and really tried to build my previous Kepler projects from scratch again under Luna. Including the SVN aspects.

Steps to recover and get a working LUNA – SVN implementation again

The following sequence of steps worked in my case:

  • First, make copies of your projects AND the associated SVN repositories. You never know ….
  • Check in all files and directories in all of your projects with the old Eclipse version (in my case Kepler) to get the latest versions into the existing SVN repository.
  • If one of the previous SVN repositories used under Kepler is corrupted (according to SVN messages in Eclipse) – do not use it any longer in the steps below. Build a new repository location instead.
  • Disconnect all existing Kepler projects from SVN via the context menu of the project by using the menu points “Team >> Disconnect” and allow for a deletion of the SVN information from disk.
  • Important point: Remove all remaining “.svn” files inside your Eclipse projects which may have remained there by using the command
    find . -name “.svn” -exec rm -fR {} \;
  • Go to the SVN repositories that still worked in Kepler (wherever they may reside) and upgrade by “svnadmin upgradeconsistently to the present SVN version – in my case 1.8.
  • Systematically restore your basic projects – i.e. the ones on which other projects may depend – from scratch by using the upgraded repositories. Or share these projects again with reference to the upgraded repository from which you then update the files to the latest repository version.
  • If one of the last steps is not possible due to repository corruption you build up new projects in Eclipse and fill them with the files from your (Kepler) project backups. Then share them by using a new repository location of your choice. Check that all SVN transactions work as expected for your basic projects.
  • Only then rebuild your more complicated projects depending which depend on your basic projects and share them again with the upgraded SVN repositories or newly generated ones.

And in the future:

Follow a systematic approach to upgrade your SVN repositories consistently to Subversion versions your Eclipse installation AND your other tools of your Linux desktop can handle.

Finally: Have fun with Eclipse LUNA and PHP or JS/Ajax projects. It feels great so far ….

MariaDB, LibreOffice 4.x, Konnektoren – Performance Problem wg. Primary Keys

Vor einigen Tagen habe ich für ein Projekt verschiedene Varianten des direkten Zugriffs von Office-Anwendungen (MS Office, Libreoffice unter Windows und Linux) auf MariaDB -(MySQL-) Datenbanken eines Remote Linux-Server getestet. Dabei habe ich mir für LibreOffice [LO] unterschiedliche Konnektoren für den Datenbankzugriff angesehen – JDBC, ODBC und den direkten, nativen Zugriff über einen MySQL-Konnektor. Letzterer wird unter Opensuse -Linux mit dem LibreOffice RPMs mitgeliefert. Unter Windows steht der Konnektor dagegen als LO-“oxt”-Extension zur Verfügung. Siehe:
http://extensions.libreoffice.org/extension-center/mysql-native-connector-for-libreoffice-4.x/releases/1.0

Bei den Performance-Tests hatte ich dann ein Erlebnis der Sonderklasse, das sicher auch andere interessieren dürfte.

Testvoraussetzungen

Libreoffice habe ich mir in der Version 3.6, der Version 4.0.3 aus dem aktuellen LO Stable Repository des Build Services von Opensuse (12.3) unter Linux angesehen. Unter Windows die Versionen 3.6.7 und 4.0.6. Die Clients (Opensuse 12.3) und Windows 7 unter VMware liefen auf ein und demselben System mit einem i7 Quad 950 Prozessor und Raid-10-System. Der Server ist ein von Strato gehosteter V-Server mit 100Mbit -Anbindung ans Internet und 32Bit Opensue 12.3. Als RDBMS wurde eine MariaDB installiert, die bei Opensuse ja die Nachfolge des MySQL-RDBMS von Oracle angetreten hat.

Die Performance des Serversystems ist hinreichend – wir führen dort Simulationsrechnungen für industrielle Prozess- and Supply Chain Netze mit mehreren Zig-Tausend Knotenpunkten und mehreren zig-tausend Datenbanktransaktionen in wenigen Sekunden durch. Für das bisschen Transfer von Tabelleneinträgen im Bereich von 100 KByte bis zu wenigen MByte zu einem Client reicht die Serveranbindung völlig.

Alle Tests wurden mit SSH-Tunnelverbindungen zum Server durchgeführt. Wie man solche Verbindungen absichert, ist in einem vorhergehenden Artikel
https://linux-blog.anracom.com/2013/11/22/ssh-getunnelter-datenbankzugang-fur-gehostete-lamp-server-i/
ausführlich erläutert. Unter Windows wurden diese Verbindungen über PuTTY realisiert.

Die konkret untersuchten Tabellen hatten zwischen 200 und 220.000 Einträgen. Es handelte sich durchweg um MyISAM- und nicht um InnoDB-Tabellen.

Das Laden einer Datenbanktabelle erfolgt unter LibreOffice so, dass man über BASE Datenbankverbindungen zum RDBMS eines Remote-Servers definiert. Unter CALC läst man sich dann die definierten Datenquellen anzeigen (Taste F4), wählt eine Bank und eine zugehörige Tabelle aus. Deren Werte werden dann in einem besonderen oberen Bereich des CALC-Fensters zunächst als Base-Tabelle dargestellt, die man auch zum Ändern der DB-Werte verwenden kann. Der CALC-Schirm teil sich durch F4 also in einen oberen Bereich, der an Base angelehnt ist und einen unteren Bereich, der eine normale CALC-Spreadsheet-Tabelle enthält.

Der Import der Daten der DB-Tabelle erfolgt dann durch Drag und Drop der Tabelle aus der mittels F4 angezeigten Base-Tabellen-Liste in den darunter liegenden CALC-Spreadsheet-Bereich. Alternativ wählt man in der Base-Tabellen-Anzeige alle Werte aus, wählt ferner ein Zelle im CALC-Tabellen-Bereich als Startpunkt des Imports aus und betätigt dann eine Taste für den Import.

In der CALC-Spreadsheet-Tabelle wird dann ein mit der Datenbank assoziierter Bereich angelegt, der nach etwas Wartezeit mit den RDBMS-Tabellen-Daten gefüllt wird. Dieser mit der Datenbank verbundene Bereich kann später jederzeit mit den aktuellen Daten des RDBMS-Systems upgedated werden. Details hierzu findet man in der LO-Hilfe.
Ich gehe hierauf in diesem Artikel nicht weiter auf di CALC-Anbindung an ein Remote-RDBMS ein.

Erste Tests: Erhebliche Performance-Unterschiede zu MS Excel ??

Der Schock entstand über einen Befund, den ich erst gar nicht glauben wollte. Nach etlichen Stunden, viel Konfigurationsarbeit und vielen Tests mit Zeitmessungen hatte ich folgendes Ergebnis vor mir:

Das reine Laden großer Datenbanktabellen über einen ODBC-Treiber schien unter Excel viel, viel schneller zu funktionieren als unter dem Gespann LibreOffice/Base/Calc mit direktem SQL-Konnektor.

Ich spreche hier wie gesagt von Tabellen mit 10.000 bis 220.000 Einträgen. [Das ist für die Belange des Kunden nicht besonders viel.] Und “schneller” ist dabei so zu verstehen, dass die Kombination Excel 2010/ODBC unter Windows 7 (64Bit) in den Tests zunächst erheblich – d.h. um Faktoren – schneller lief als jede Connector-Variante (ODBC, Direct MySQL-Connector, JDBC) mit Libreoffice/Calc/Base.

Dabei läuft Win 7 bei mir nur unter VMware. Die Linux-Tests wurden auf demselben nativen Linux-Host durchgeführt, der auch VMware beherbergt.

Ich nenne ein paar Zahlen für Tabellen mit ca. 14 Zahlenspalten (Integer, Double) :

  • Laden/Importieren Tabelle mit 224 Records : ca. 1 Sek.
  • Laden/Importieren Tabelle mit 6000 Records : ca. 8 Sek.
  • Laden/Importieren Tabelle mit 60.000 Records : ca. 95 Sek.
  • Laden/Importieren Tabelle mit 138.000 Records : ca. 4:40 Min.

Updates dieser per Base nach CALC importierten Tabellen dauerten etwa genauso lange. Den Versuch, eine Tabelle mit 250.000 Records zu laden, habe ich nach mehr als 10 Minuten Wartezeit abgebrochen. Ich merke ausdrücklich an, dass diese Zeiten nicht durch die übertragene Datenmenge über eine evtl. schlechte Internetanbindung erklärbar sind. Ferner gilt/galt:

Dem gegenüber stand eine Zahl für das Laden einer Tabelle mit 138.000 Records nach Excel per ODBC Konnektor von nur ca. 6-8 Sekunden.

Ich empfand diese extreme Diskrepanz zu Linux wirklich als unakzeptabel.

Man muss dazu sagen, dass die genannten Zahlen für das Linux-System bereits optimale Werte darstellen. Typischerweise ergaben sich auch sehr seltsame Effekte, wenn man zwischen den Tests die LO-Versionen durch Neuinstallationen der RPMs wechselte und die Konfigurationsdateien des aktuellen Linux-Users nicht komplett löschte. Teils lief dann das Laden auch kleiner Tabellen unter Calc unendlich lang. Ich deute diese Instabilitäten im Zusammenhang mit Up- oder Downgrades der RPMs – auch bei Auflösung aller Abhängigkeiten. Vielleicht ist das ein Hinweis darauf, dass irgendwelche Überbleibsel und Konfigurationseinstellungen nach einer Neuinstallation noch zu Interferenzen führen.

Die oben genannten Werte stellten sich nur ein, wenn man die jeweiligen Konfigurationsverzeichnisse im Home-Verzeichnis des Linux-Users nach einem Up- oder Downgrade vollständig gelöscht hatte. Ich konnte sie ferner nur für die 4.0.x-Version erzielen. Die Zeiten unter der 3.6 Version waren z.T. noch erheblich länger.

Schlechte Performance-Werte auch unter Windows

Der wirklich frustrierende Befund für die Datenanbindung von LO an eine MySQL-Datenbank wurde leider durch nachfolgende Tests für die LO-Versionen 3.6 und 4.1.3 unter Windows voll bestätigt.

Einschränkend sei angefügt, dass die Philosophie dessen, was ein Load/Import von Datenbankdaten leisten muss, vermutlich in Excel etwas anders ist als in LO. Aber beide Systeme verankern Datenbank-Verbindungen – in BASE geschieht dies innerhalb der Applikation, unter Windows werden die ODBC-Verbindungen über die Systemsteuerungen im Betriebssystem hinterlegt.

Excel lädt
und importiert auf den ersten Blick eher passiv; auf der LO-Seite sind dagegen jederzeit Änderungen der DB-Inhalte und nachfolgende Updates aus der Datenbank für spezielle datenbank-assoziierte “Bereiche” von Calc-Tabellen möglich. Dennoch:

Schon beim Hantieren unter LO-BASE fallen die Geschwindigkeitsunterschiede ins Auge: BASE aktualisiert bereits beim Scrollen über große Tabellen die angezeigten Daten laufend im Hintergrund aus der angeschlossenen Datenbank. Ich habe keine Einstellung gefunden, das zu unterbinden. Vielleicht war ich dazu schlicht zu blöd.

Es zeigte sich unter Windows zudem, dass ein ODBC-Konnektor fast die gleichen Zeitwerte für den Datenbank-Import nach CALC lieferte wie die direkte MySQL-Anbindung durch den MySQL-Konnektor. Leider erwies sich die Performance einer JDBC-Anbindung noch deutlich schlechter als die der MySQL- und des ODBC-Konnektoren. Dass mindestens der ODBC-Konnektor aber eigentlich deutlich mehr leisten kann, beweisen gerade die hervorragenden Ladezeiten für Excel.

Performance-Problem des MySQL-Konnektors wegen Primary Keys?!

Die Frustration spornte mich zu weiteren Experimenten an. Ganz zufällig stieß ich dann bei weiteren Test unter Linux auf ein Tabelle mit 78.000 Einträgen. Überraschenderweise galt für diese Tabelle: Statt Minuten warten zu müssen, konnte ich die Tabellen-Daten in ca. 4-5 Sekunden über BASE/CALC in ein Calc-Spreadsheet laden.

Bei der weiteren Analyse stellte sich dann heraus, dass ich vergessen hatte, für diese Tabelle einen expliziten Primary Key festzulegen. Das führte zu dem Verdacht, dass explizit definierte Primary Keys evtl. mit verantwortlich für die schlechte Performance der LibreOffice-Anbindung waren – so idiotisch sich das auch anhören mag ….

Lösung: Ersetze Primary Keys durch Unique Keys !

Natürlich habe ich dann mal testweise auch in anderen Tabellen die explizit definierten PRIMARY Keys gedropt und durch schlichte UNIQUE-Keys ersetzt. Ja, das geht: MySQL oder Maria DB nehmen laut Doku stillschweigend den ersten passenden UNIQUE Key und setzen ihn als Primary Key ein. Große Probleme habe ich diesbzgl. bislang nicht erlebt.
Ergebnis meiner Versuche war:

Bei allen Tabellen, in denen der explizit gesetzte Primary Key durch einen reinen Unique Key ersetzt wurde, erfolgte der Daten-Import in LibreOffice-CALC mit annehmbaren Zeiten, die sich von denen von Excel nur noch wenig unterschieden (Faktor < 1,25).

Dabei ergab sich durch gleichzeitiges Beobachten der Datenbank und der Netzverbindung der begründete Eindruck, dass CALC nach dem eigentlichen Laden der Daten aus dem RDBMS noch erhebliche Zeit für den internen Aufbau der CALC-Tabelle aufwendet. Nurmehr Letzteres und nicht mehr das Laden der Daten aus der Bank selbst erwies sich für die vom Primary Index befreiten Tabellen als verantwortlich für die noch feststellbaren Zeit-Unterschiede gegenüber Excel beim Füllen der lokalen Spread-Sheet-Tabellen.

Konkret ergab sich für das Laden der Tabelle mit 138.000 Records eine Zeit von knapp unter 8 Sekunden – anstatt der früheren fast 5 Minuten.

In unserem Projekt habe ich nun in allen RDBMS-Tabellen explizit definierte Primary Keys durch Unique Keys ersetzt. Seitdem können die Anwender auch mit CALC prima auf der MariaDB-Datenbank arbeiten.

Offene Frage : Wieso behindern Primary Keys die LibreOffice Performance so drastisch?

Ich habe leider keine plausible Antwort. Diese Frage müssen die Entwickler der MariaDB klären. Auffällig ist die dauerhaft hohe Transaktionsrate auf dem Server von insgesamt über 200 Transaktion /sec, wenn ein Primary Key vorhanden ist.

Ich sollte abschließend noch betonen, dass ich den positiven
Befund für das Entfernen der Primary keys explizit nur für eine MariaDB getestet habe. Es wäre sicher interessant, das Performance-Verhalten auch unter einer nativen Oracle-MySQL-Datenbank zu untersuchen. Hierfür habe ich leider noch nicht genügend Zeit gefunden.