Javascript: Einsatz des new-Operators mit Variablen und dynamischer Vorgabe der Konstruktorfunktion

In PHP gibt es die Möglichkeit, den “new” Operator mit einer Variablen zu kombinieren. Dies entspricht einer indirekten Adressierung des Konstruktors. Beispiel :

$ClassName = "Class_Test"; 
$Obj = new $ClassName( param1, param2, ...); 

 
Probiert man etwas Ähnliches unter Javascript, so erleidet man Schiffbruch. Der String-Wert einer Variablen wird vom “new” Operator nicht als Bezeichnung einer Konstruktorfunktion interpretiert.

Sieht man typische Webseiten oder auch Bücher nach der Verwendung des “new”-Operators durch, so wird nach dem “new”-Operator fast durchgehend die Benutzung eines Literals beschrieben, das dem Namen der definierten Funktion entspricht:

function meterpreter() {
	this.alpha = 5; 
}      
var Obj = new meterpreter(); 
echo "value of property alpha = " +  Obj.alpha;    

 
Die Verwendung eines Literals scheint eine indirekte, dynamische Adressierung auszuschließen.

Nun passiert es einem aber auch unter Javascript, dass man ein Objekt gerne aus einem dynamischen Kontext heraus erzeugen möchte. Dann will man den “new”-Operator mit einer Variablen kombinieren, die dynamisch ermittelt wurde, und deren Wert irgendwie die Konstruktorfunktion referenzieren soll. Ein Beispiel:

Man möchte beim Startup einer Webseite eine Reihe von (Singleton-) Objekten erzeugen. Die Namen der zugehörigen
Konstruktorfunktionen seien in einem Array gespeichert. Ein Loop über das Array könnte die Objekterzeugung durchführen, wenn der “new”-Operator mit dem jeweiligen Array-Eintrags verbunden werden könnte und dadurch dann indirekt auch der jeweils benötigte der Konstruktor aufgerufen werden würde. Wie also nutzt man den “new”-Operator zusammen mit Variablen unter JS?

Hier hilft es, sich daran zu erinnern, dass definierte JS-Funktionen Objekten entsprechen, die sich Variablen zuordnen lassen. Nehmen wir in Anlehnung an das obere Beispiel an, wir hätten ein globales Objekt definiert, dass wir GOC (Global Object Controller) nennen wollen und das ein Array mit Namen für potentielle (Singleton-) Objekte beinhaltet. Nehmen wir ferner an, dass wir zugehörige Konstruktorfunktionen bestimmten Variablen des GOC mit normierten Namen zugeordnet hätten:

this.GOC = new Global_Object_Controller();  
this.GOC.createObjects(); // hier konstruieren wie Objekte als Elemente des GOC

function Global_Object_Controller() {
	this.ay_ctrl_obj_names  = new Array('Gallery', 'Ajax', ....);
	this.num_ctrl_objs = this.ay_obj_names.length;

	// Konstruktor Definition
	// ----------------------- 
	this.Constr_Gallery = function( param ) {
	 	.....	
		this.alpha = param + 1; 
		.....
		.....
 	};

	// Method definition of Constr_Gallery 
	// Wir verwenden zur Abwechslung mal die an Arrays angelehnte Notation ...
	this['Constr_Gallery'].prototype.do_something = function() {
		...
		this.obj_num += 10; 
		...
	};  
	.....
	..... 	

	// Konstruktor Definition
	// ----------------------- 
	this.Constr_Ajax = function( param ) {
	 	.....	
		this.obj_num = param + 1; 
		.....
		.....
 	};
	....
	....
}

 
Dann können wir z.B. über eine Methode tatsächlich Objekte dynamisch erzeugen lassen – und zwar z.B. über folgenden simplen Trick:

Global_Object_Controller.prototype.createObjects = function() {
	
	var ctrl_obj_name = ''; 
	var constr_name = ''; 
	....
	for (i=0; i<this.num_ctrl_objs; 
i++) {
		...
		ctrl_obj_name = "Obj_" + this.ay_ctrl_obj_names[i]; 
 		constr_name   = "Constr_" + this.ay_ctrl_obj_names[i];

		// Indirekter Aufruf des Konstruktors über eine Variable (hier des GOC)  
		// *******************************************************************
		this[ctrl_obj_name]  = new this[constr_name](i); 
		// ******************************************************************** 		
		// ist identisch mit 
		// window.GOC[ctrl_obj_name] = new window.GOC[constr_name](i); 		
	
		// console.log("Objekt " + ctrl_obj_name + " im GOC kreiert");  
  		....
	}	
	.....
	// console.log("Obj_Gallery.obj_num = " + this["Obj_Gallery"].obj_num ); // value=1 
	this["Obj_Gallery"].do_something(); 
	// console.log("Obj_Gallery.obj_num = " + this["Obj_Gallery"].obj_num ); // value=11  
	// console.log("Obj_Ajax.obj_num = "    + this["Obj_Ajax"].obj_num );    // value=2  
	
	.....
};   

 
Das funktioniert! Man erkennt, dass in unserem sehr simplen Beispiel die gewünschten Objekte über Variablenaufrufe als Elemente des GOC-Objekts erzeugt werden.

Man kann den “new”-Operator also tatsächlich mit Variablen (irgendwelcher Objekte oder von “window”) kombinieren, wenn diesen Variablen bereits sinnvolle Konstruktorfunktionen zugeordnet wurden. Das erinnert an den Callback-Mechanismus – hier allerdings für den “new”-Operator.

Die indirekte Adressierung erfolgt im Gegensatz zu PHP dadurch, dass man den “Namen” der Variablen im Zuge des Algorithmus dynamisch festlegt und darüber dann auf den Konstruktor als das Funktions-Objekt referenziert. Das erfordert zwar ein etwas anderes Vorgehen, schränkt einen aber im Vergleich zu PHP in der Zielerreichung einer dynamischen und indirekten Konstruktor-Referenzierung nicht ein.

Dadurch wird man bzgl. der Objektgenerierung sehr viel flexibler, als wenn man sich immer mit Literalen herumschlagen müsste.

Off Topic:

Das Beispiel zeigt übrigens, dass Konstruktorfunktionen nicht immer zwingend im globalen Kontext (window) platziert werden müssen. Sie können auch jederzeit Variablen eines bereits definierten übergeordneten Objekts (oder seines Konstruktors) zugeordnet werden. Dies eröffnet in bestimmten Fällen weitere Möglichkeiten der Kapselung von Code.
In der Praxis muss man sich eine Zuordnung von Konstruktor-Funktionen zu Variablen aber gut überlegen. Schon aus Gründen der Codeverwaltung wird man Konstruktorfunktionen für wichtige Objekt in separaten, eigenen Dateien aufbewahren. Beim Laden der Dateien werden die Funktionen dann typischerweise in den globalen Kontext platziert.
Zudem gilt: In komplexen Codes, die z.B. mit Eclipse oder anderen Tools gewartet werden, ist die Zuordnung von Konstruktorfunktionen zu Variablen eines anderen Konstruktors möglicherweise mit dem Nachteil verbunden, dass Code-Outliner diese Sub-Konstruktoren, zugehörige Variable und Funktionen ggf. nicht mehr als eigene Objekte ausweisen – sie sind dann einer einfachen Navigation im Code über den Outliner nicht mehr zugänglich.

Will man die Konstruktoren deshalb aus guten Gründen unabhängig von anderen Objektbeschreibungen definieren, so ist das Codebeispiel leicht zu modifizieren: Man definiert die Konstruktorfunktionen global und nicht im GOC. Und ruft sie dann im GOC und dessen Loop wie folgt auf:

this[ctrl_obj_name] = new window[constr_name](i);

Viel Spaß weiterhin mit Javascript!

Hilfreiches Eclipse Plugin: wtp-webresources

Ich versuche ja gerade, meine Frau dazu zu bringen, statt des proprietären und nicht linux-tauglichen und wenig stabilen Dreamweavers die IDE Elipse für HTML und CSS Coding zu benutzen. Zur Auswahl stehen dort die Web Standard Tools (WST) oder z.B. das Aptana Studio Plugin. Nun zieht die Installation des Aptana Plugins immer noch einige unangenehme Nebeneffekte nach sich, so dass man sich lieber mit den Editoren der nativen Eclipse Web Developer Tools begnügen möchte.

Ein Nachteil des WST Eclipse HTML Editors für Eclipse-Umsteiger ist u.a. folgender:

Man erhält zwar Code Assist Vorschläge bzgl. elementarer CSS2- oder CSS3-Anweisungen für Inline-Styles. Beim Editieren des “class”-Attributs eines HTML-Tags erhält man jedoch keine Assist-Angebote zu bereits definierten Style-Anweisungen für Classes, die in CSS-Dateien eines Eclipse-Projekts enthalten sind – auch dann nicht, wenn man solche CSS-Dateien bereits explizit im HEAD-Bereich der HTML-Datei eingebunden hat. Umgekehrt erhält man bei einem Hover über die Klassendeklaration eines HTML-Tags keine Informationen zu den zugehörigen Style-Festlegungen.

Ähnliche Defizite gibt es im Bereich der Ergänzung von Bild-, CSS-File- und JS-File-Ressourcen. Hier ließen sich Content Assist Angebote ja prinzipiell über die Inhalte der Projektverzeichnisse zusammenstellen.

Das Plugin “wtp-webresources” behebt all diese Schwächen und ist damit ein wirklich nützliches, empfehlenswertes Helferlein für Eclipse Mars. Siehe:
https://github.com/angelozerr/eclipse-wtp-webresources

Ob das meine Frau überzeugen wird, weiß ich noch nicht – der nächste Punkt, den sie im Vergleich mit Dreamweaver mit Sicherheit vermissen wird, ist eine Darstellung der effektiv wirksamen CSS-Styles für ein HTML-Tag aus der Kombination der für das Tag festgelegten “id”-bezogenen, “class”-bezogenen Styles, aktuellen Inline-Styles und zugehöriger Spezifizitätsregeln. Wäre auch in Eclipse nützlich ….

Opensuse Leap 42.1 und 13.2 – aktuelle Versionen des freshplayerplugin-Pakets führen zum Crash von Eclipse mit GTK2

Es gibt Probleme, deren Ursachen sind schwer zu finden und können einen in den Wahnsinn treiben. So zuletzt das Phänomen, dass Eclipse mit GTK2 nach Updates sowohl von Opensuse 13.2 als auch Opensuse Leap 42.1 permanent und zunächst scheinbar erratisch abstürzten.

Interessanterweise tauchen die Probleme mit Eclipse unter GTK3 nicht auf. Allerdings zeigt die Eclipse UI unter GTK3 noch einige unschöne Grafik-Probleme.

Es dauerte eine Weile, bis ich herausfand, dass die Abstürze von Eclipse/GTK2 nur auftraten, wenn ich Content Assist Funktionalitäten benutzte (was ich natürlich sehr regelmäßig tue) und dabei Zusatzinformationen zu Elementen der Vorschlagsliste angezeigt wurden. Typischerweise ist es so, dass diese Zusatzinformationen aus HTML-Vorgaben gerendert werden. Die Java Runtime JVM nutzt hierzu “webkit”-Funktionalitäten (der Umgebung).

Es dauerte noch einige Zeit mehr, bis ich herausfand, dass das Problem auf einer frischen Installation von OS 13.2 oder LEAP 42.1 nicht auftrat – wohl aber nach einer Reihe von Updates der Opensuse-Umgebung. Leider ist es durchaus schwierig, herauszufinden, welches Paket unter hunderten genau der Verursacher der Probleme ist. Dass es mit Web/HTML-Rendering zu tun haben musste, war aber klar.

Durch eine Backtrace-Analyse des JVM-Absturzes kam ich heute einen substanziellen Schritt weiter:

Die erhaltenen Absturz-Informationen der JVM zeigten, dass im Rendervorgang auch eine “freshwrapper”-Bibliothek tangiert wurde – genauer:
“/usr/lib64/browser-plugins/libfreshwrapper-pepperflash.so” aus dem Paket freshplayerplugin.

Das Paket “freshplayerplugin” liefert einen nützlichen Firefox-Wrapper für Chromes/Chromiums “pepper-flash”-Plugin. Letzteres ermöglicht das Abspielen von Flash-Inhalten auch unter Firefox – das ist u.a. nützlich für Live-Streams des einen oder anderen Fernsehsenders, der bislang noch nicht auf vernünftige Formate umgestellt hat.

Ich hatte das Paket “freshplayerplugin” unter Leap 42.1 und OS 13.2 im Zuge von Updates in der aktuellsten Variante “0.3.4-20.1” vom Packman-Repository installiert.

Tatsächlich zeigte sich, dass mit einer Installation der Paketversion “0.3.2” aus den jeweiligen Hauptrepositories von SuSE die Eclipse-Absturz-Probleme unter Opensuse Leap 42.1 verschwanden. Bzgl. OS 13.2 muss ich mich noch kundig machen.

Ich hoffe, diese Info zumindest zu Leap 42.1 hilft auch anderen Betroffenen, die Eclipse mit GTK2 nutzen wollen.

PHP and web application security – bad statistics and wrong conclusions

Sometimes I have discussions with developers of a company working mainly with Java. As I myself sometimes do development work with PHP I am regarded more or less as a freak in this community. Typical arguments evolve along the lines:

“PHP does not enforce well structured OO code, no 4-layer-architecture built in, problems with scalability”, etc…. I do not take these points too seriously. I have seen very badly structured Java OO code, one can with proper techniques implement web services in a kind of logical 3rd layer on special servers and Facebook proves PHP scalability (with some effort), etc…

What is much more interesting for me these days is the question how security aspects fit into the use of different programming languages. And here comes the bad news – at least according to statistics published recently by the online magazine Hacker News – see
http://thehackernews.com/2015/12/programming-language-security.html

The statistics on OWASP 10 vulnerability types of the investigated PHP code looks extremely bad there – compared to the investigated Java code examples. I admit that this is an interesting result for hackers and that it is somewhat depressing for security aware PHP developers.

However, is this the bad statistics the fault of the programming language?

I doubt it – despite the fact that the named article recommends to “Choose Your Scripting Language Wisely”. I would rather recommend: Educate your PHP developers properly and regularly, implement a proper quality assurance with special security check steps based on vulnerability scanning tools and invest in regular code reviews. Why?

The investigation revealed especially large deviations in the fields of XSS, SQL-injection, command injection (major elements on the OWASP 10 list). The countermeasures against the named attack vectors for PHP are all described in literature and very well known (see e.g. the books “PHP Sicherheit” of C.Kunz, S.Esser or “Pro PHP Security” of Snyder, Myer, Southwell). One of the primary key elements of securing PHP applications against attacks of the named types is a thorough inspection, analysis and correction treatment of submitted GET/POST-parameters (and avoidance of string parameters wherever possible). Never trust any input and escape all output! Define exceptions wisely and rewrite sensitive string elements according to your rules. Check whether input really comes from the right origin – e.g. your own domain, etc., etc.

Whether all relevant security measures are implemented in the PHP code of a web application has therefore more to do with the mentality, technical ability, the knowledge and on the negative side with the laziness of the programmer than with the programming language itself. As at least the technical capability is a matter of education, I conclude:

Tests regarding type, value range, length and of course tests of the contents of received string variables and e.g. image source references plus sanitizing/elimination/deactivation of problematic contents as well as the proper use of respective available library functions for such tests should be part of regular PHP training programs. In addition the use of web application scanning tools like OWASP’s ZAP scanner or the Burp Suite Pro (if you have money to afford the latter) should be trained. Such tools should become part of the QA chain. As well as educated penetration testers with the perspective of the attacker …. The money a SW-company invests for such educational measures is well invested money.
See for the significant impact of education e.g.:
https://seclab.stanford.edu/websec/scannerPaper.pdf

I would regard the statistical results discussed in the “Hacker News” article much more conclusive if we were provided additional information about
the type of applications analyzed and also the size and type of the companies behind the application development. And whether and what type of QA efforts were used. This would give a much better indication of why the Java code showed more quality regarding the prevention of OWASP 10 attacks. One reason could e.g. be that Java applications very often are developed for enterprise purposes – and bigger companies typically invest more time and effort into QA …

So, another valid interpretation of the presented statistics could be that the QA for typical PHP web application SW is on average worse than for Java SW. I admit that such a finding would also be very interesting – but it does not prove that one cannot write secure Web applications with PHP or that the production of secure code is for whatever reasons easier with Java.

In addition the presented number of bugs per MB itself is questionable: if you only look at 3 bad PHP examples and 1 good Java example you may get the same type statistics – but it would be totally meaningless. The distribution of PHP-, Java-, JS-code etc. among the statistical sample is, however, nowhere discussed in the named article – neither in number of applications nor in MB percentages.

Therefore: Without further information the implied conclusion that already the proper choice of a web scripting language would help to improve security of web applications appears is misleading.

To improve the mood of PHP developers having read the article in “Hacker News”: Have a look at the results of a similar investigation presented at this link
http://info.whitehatsec.com/rs/whitehatsecurity/images/statsreport2014-20140410.pdf

See also:
https://blog.whitehatsec.com/a-security-experts-thoughts-on-whitehat-securitys-2014-web-stats-report/
https://www.scriptrock.com/blog/which-web-programming-language-is-the-most-secure
https://threatpost.com/security-begins-with-choice-of-programming-language/105441/

It may help, really !

[But keep in mind: Only trust statistics you have manipulated yourself.]

MySQL – effiziente Prüfung von Tabellenspalten auf (ausschließlich) vorhandene Default-Einträge

Einige meiner Leser wissen, dass ich mich für PHP-basierte Simulationsrechnungen mit dem Thema des Uploads von CSV-Daten-Files für viele Tabellen befassen muss. Nun haben wir eine Situation, in der eine Tabelle zwar viele Spalten enthalten kann, aber für bestimmte Simulationen nicht alle Spalten zwingend mit Werten gefüllt werden müssen. Um die Upload-Zeiten gering zu halten, werden diese Spalten in den CSV-Dateien gar nicht übermittelt. Das durchzuführende LOAD DATA INFILE Statement wird entsprechend angepasst und versorgt die Spalten, für die das File keine Daten liefert, mit Default-Werten.

Nun erfordert jede unserer Simulationsrechnungen eine vorherige Prüfung von Konsistenzbedingungen. Dabei ist es u.a. wichtig, welche Spalten ausschließlich mit Default-Werten gefüllt wurden und welche nicht. Die Meinung eines beteiligten Entwicklers war, dass man diese Information – wenn nötig – unmittelbar aus dem tatsächlich gegebenen Tabellenzustand ermitteln sollte, um immer eine verlässliche Entscheidungsgrundlage zu haben.

Als Voraussetzung nehmen wir an, dass wir aus Platzgründen keine Indices für die einzelnen oder gekoppelten Daten-Spalten der zu untersuchenden Tabelle angelegt haben.

Abfrage über mehrere SQL-Statements für jede Spalte

Der erste naive Anlauf war dementsprechend, in mehreren SQL-Abfragen Spalte für Spalte auf die Anzahl der gesetzten Default-Werte zu prüfen und mit der Gesamtzahl der Tabellen-Records zu vergleichen. Das einzelne Select würde dann etwa so aussehen:

SQL-Typ1:
SELECT COUNT(*) FROM myTable WHERE colx=defaultValue;

Das Ganze pro Spalte für alle zu untersuchenden Tabellen. Ein solches Vorgehen erschien mir ineffizient – insbesondere wenn eine Tabelle viele zu untersuchende Spalten aufweist und man das Ganze für viele Tabellen machen muss. Der Grund:

Jede dieser Abfragen führt einen Full Table Scan durch, denn man wird in den seltensten Fällen einen Index über jede einzelne Spalte oder alle Spalten gelegt haben.

Wir reden in unserem Fall zudem über potentiell große Tabellen mit mehreren 10-Millionen Einträgen.

Ist die Abfrage in einem einzigen SQL-Statement effizienter?

Zunächst dachte ich deshalb darüber nach, ob man die Aufgabe nicht in einem einzigen Statement durchführen kann. Ergebnis:

SQL-Typ 2:
SELECT
SUM(IF(col1 = default_val_col1, 1,0)) as num_def_col1,
SUM(IF(col2 = default_val_col2, 1, 0)) as num_def_col2,
SUM(IF(col3 = default_val_col3, 1, 0)) as num_def_col3,


SUM(IF(coln = default_val_coln, 1, 0)) as num_def_coln
FROM myTable;

Das ist zwar schön und der Ansatz ist sicher für bestimmte andere Auswertungen auch von grundsätzlichem Interesse (s. etwa: http://www.randomsnippets.com/2008/10/05/how-to-count-values-with-mysql-queries/). So kann man ähnliche Statements z.B. einsetzen, wenn man herausfinden will, wie oft vorgegebene, unterschiedliche Werte in genau einer Spalte vorkommen.

Aber ist das in unserem Fall vom Zeitbedarf her wirklich effizienter als der erste Ansatz? Die Antwort lautet: Nur geringfügig.

Die folgenden zwei Abbildungen zeigen typische Werte für SQL-Typ 1 und SQL-Typ2 auf einem einfachen Testserver für eine Tabelle mit ca. 10 Millionen Einträgen und 6 untersuchten Wertespalten:

Messung für Statement vom SQL-Typ1 für eine Spalte

sqlff1

Messung für Statement vom SQL-Typ2 für 6 (!) Spalten

sqlff2

Wir kommen (nach Multiplikation mit der Anzahl der Spalten) auf etwa 6 sec für Typ1 und 5.3 sec Gesamtlaufzeit für Typ2. Der Unterschied ist also nicht weltbewegend. (Hinweis: Ein zusätzlich durchzuführendes Count(*) kostet praktisch keine Zeit; wir haben das hier deshalb weggelassen.)

Warum erhalten wir solch ein Ergebnis?
Nun die Anzahl der zu treffenden Entscheidungen ist praktisch identisch und gezählt wird in beiden Fällen. Demgegenüber tritt das mehrfache Durchlaufen der Tabelle bei Typ 1 zum systematischen Bereitstellen der Daten einer Zeile in den Hintergrund. Im besonderen, wenn die Tabelle schon im Cache vorliegen sollte.

Noch ineffizienter wird ein Ansatz, bei dem mit COUNT(Distinct) gearbeitet würde und bei den Spalten die nur einen Wert aufweisen, diesen Wert zusätzlich ermittelt würde :

Allein das Statement für unsere Testtabelle

SELECT COUNT( DISTINCT sssim ) AS dist_sssim, COUNT( DISTINCT mult ) AS dist_mult, COUNT( DISTINCT dobs ) AS dist_dobs, COUNT( DISTINCT sigmad ) AS dist_sigmad, COUNT( DISTINCT sigmalt ) AS dist_sigmalt, COUNT( DISTINCT fexp ) AS dist_fexp
FROM `alien_ss_comb_itm`

dauert hier 7.6 sec. Dies liegt daran, dass hier temporäre Datenstrukturen bzw. Tabellen erzeugt werden.

Die langsamste Abfrage-Alternative

Es gibt natürlich eine weitere Alternative zum Typ 1 – Statement:

SQL-Typ3:
SELECT colx as dist_colx, COUNT(colx) as num FROM myTable GROUP BY colx;

Die Anzahl der Treffer, der Ausgabewert “num” und der ggf. gefundene alleinige Wert können auch hier dafür verwendet werden, um festzustellen, ob die Spalte nur mit Default-Werten gefüllt ist.
Für dieses Statement dauert in unserer Testtabelle die Abfrage über eine einzige Spalte allerdings bereits 2.5 sec:

sqlff3

Auch hier ist das Anlegen von temporären Datenstrukturen und der erforderliche Einsatz von Filesort in der MySQL-DB die Ursache der schlechten Performance.

Zu kostspielig? Alternativen?

Offenbar ist so eine Prüfung für große Tabellen relativ kostspielig. Mehrere Sekunden, um festzustellen, welche Spalten mit regulären Daten gefüllt wurden? Geht gar nicht …

Zugegeben: Das hängt immer davon ab, in welchen Zusammenhang – also Art von Upload- oder Serverlauf – man eine solche Prüfung einbettet. Dauert ein Simulationslauf für große Tabellen 15 Minuten, so sind 5 sec egal. Auch bei Uploadzeiten von 50 sec kann man 10% Zuwachs verschmerzen. Auch zugegeben: Man ist von keiner weiteren Information außer dem aktuellen Tabellenzustand selbst abhängig.

Würde das Anlegen eines Index pro Spalte helfen?
Natürlich würde das SQL-Statements vom Typ 1 extrem beschleunigen! Aber kann man sich Indices pro Spalte denn bei großen Tabellen überhaupt leisten? Wohl eher nicht: Indices kosten u.U. und je nach Kardinalität enorm viel Platz und ihr Anlegen erhöht den Bedarf an CPU-Zeit im Rahmen eines Dateiimports beträchtlich. Wenn man also Indices über einzelne Daten-Spalten nicht noch für andere Zwecke benötigt, sollte man deshalb eher die Finger davon lassen.

Beschleunigung von erforderlichen Abfragen auf den Füllgrad von Spalten mit
Defaultwerten über eine Hilfstabelle

Muss man die vorgesehene Prüfung überhaupt über SQL-Abfragen auf den Spalten der zu untersuchenden Tabelle machen?

In unserem Fall, in dem es nur darum geht, ob in einer Spalte aussschließlich Default-Werte vorliegen, natürlich nicht! Der einzig sinnvolle Weg führt mal wieder über eine Hilfstabelle, die bereits auf Grund einer Analyse des Aufbaus der importierten CSV-Datei erstellt wird.

Im Fall der Verwendung von “LOAD DATA INFILE” genügt dabei ein Check der ggf. vorhandenen Header-Zeile mit Spaltenbezeichnungen und der ersten Datenzeile; ein solcher Check ist sowieso obligatorisch, um das “LOAD DATA INFILE” Statement um explizite Angaben zum Füllen der Spalten zu ergänzen, für die die CSV-Datei keine Daten liefert. Ein so ergänztes “LOAD DATA INFILE”-Statement ist viel schneller als das Füllen mit Defaultwerte der Bank selbst zu überlassen. Einen Check der Korrektheit der Struktur der übergebenen Daten benötigt man im übrigen sowieso.

Lösung: Auf Basis der CSV-Datei-Analyse füllt man nach einem erfolgreichen Laden der CSV-Daten in die Ziel-Tabelle zusätzlich eine kleine Hilfstabelle, in der für jede Tabelle und Spalte Werte eingetragen werden, die besagen, wie oft der Default-Wert vorliegt und ob er ausschließlich vorliegt.

Alle nachfolgenden Prüfungen greifen dann auf den Inhalt dieser Hilfstabelle zu. Das ist selbst bei einem zusätzlichen Vergleich von Zeitstempeln zwischen Hilfs-Tabelle und Original-Tabelle um Größenordnungen schneller als ein Statement vom Typ 2 – nicht nur bei großen Tabellen.

Sollte die Hilfstabelle aus irgendeinem Grunde mal nicht gefüllt sein, oder die Zeitstempel nicht passen, kann man ja in dem Programm, das die Belegung von Spalten mit Defaultwerten prüfen will, immer noch auf das Statement vom Typ 2 als Fallback zurückgreifen. Aber das ist maximal nur genau einmal erforderlich!

Genau so haben wir es dann in unserem Projekt auch gemacht!

Es liegt im übrigen auf der Hand, wie man mit ein wenig Parametrierung eine allgemeinere PHP-Funktion erstellt, die ermittelt, wie oft spaltenspezifische, vorgegebene Werte in einer importierten Datentabelle auftauchen. So ist die (dynamische) Erzeugung von SQL-Statements vom Typ 2 für Tabellenspalten ohne Index also für bestimmte Auswertungen ggf. doch von Nutzen.