=Paper=
{{Paper
|id=None
|storemode=property
|title=Minimal-Invasive Indexintegration - Transparente Datenbankbeschleunigung
|pdfUrl=https://ceur-ws.org/Vol-850/paper_adam.pdf
|volume=Vol-850
|dblpUrl=https://dblp.org/rec/conf/gvd/AdamLB12
}}
==Minimal-Invasive Indexintegration - Transparente Datenbankbeschleunigung==
Minimal-Invasive Indexintegration Transparente Datenbankbeschleunigung Alexander Adam Sebastian Leuoth Wolfgang Benn dimensio informatics GmbH dimensio informatics GmbH Technische Universität Brückenstraße 4 Brückenstraße 4 Chemnitz 09111 Chemnitz 09111 Chemnitz Straße der Nationen 62 alad@dimensio-informatics.de lese@dimensio-informatics.de 09107 Chemnitz benn@cs.tu-chemnitz.de Keywords nen schlechten Portabilität der entwickelten Module. Beson- Datenbankenerweiterung, Indizierung, Transparent ders im Bereich der Indizierung um den es in diesem Papier gehen soll, stellen sich aber noch weitere Probleme dar. Normalerweise kann ein Index auf einer beliebigen Ta- ZUSAMMENFASSUNG belle und deren Spalten definiert werden. Die Anwendung Aktuelle Datenbanksysteme bieten dem Nutzer eine enor- bemerkt nur insoweit etwas von dieser Aktion, als dass An- me Funktionsvielfalt [12, 8]. Selbst sehr spezielle Gebiete fragen schneller beantwortet werden sollten. wie z. B. Geodatentypen [9, 14] werden unterstützt. Abhän- Ein kleines Beispiel soll dies verdeutlichen. Die folgende gig vom verwendeten Datenbanksystem können diese Fä- Anfrage gibt alle Mitarbeiterinformationen zurück, die zu higkeiten durch einen Nutzer noch erweitert werden. Bei- Mitarbeitern mit mehr als 1000 Euro Gehalt gehören: spiele hierfür wären Funktionen und nutzerdefinierte Da- tentypen [12, 8]. Alle diese Erweiterungen sollten natür- Listing 1: SQL-Anfrage mit Bedingung im WHERE-Teil lich nicht die Geschwindigkeit des Datenbanksystems nega- tiv beeinflussen. So gibt es neben normalen Indexen auch SELECT ∗ Funktionsindexe und Indexe für nutzerdefinierte Datenhal- FROM mitarb tungen [20, 2]. Die Möglichkeiten, zu indizieren sind dabei, je WHERE mitarb.gehalt > 1000 nach Datenbankhersteller, vorbestimmt und selbst nicht er- Für die Anwendung, die diese Anfrage an die Datenbank weiterbar. Allen diesen Techniken ist weiterhin gemein, dass stellt, ist es vollkommen unerheblich, ob sich auf der Ge- sie direkt am Datenbanksystem ansetzen und teils auch in haltsspalte der Mitarbeitertabelle ein Index befindet oder der Anfragesprache sichtbar sind. Es ist daher nicht einfach nicht. Die Anfrage würde, ob nun mit oder ohne Index, im- möglich, eine Anwendung, die fest vorgegeben ist, mittels mer gleich aussehen. solcher Techniken zu beschleunigen. In diesem Papier wol- Wir nehmen nun an, dass die Gehaltsspalte durch einen len wir eine Möglichkeit vorstellen, mit der eine solche Be- anderen Typ ersetzt werden soll, Gründe hierfür könnten ei- schleunigung auch dann noch möglich ist, wenn weder das ne effizientere Speicherung oder bessere Zugriffsmöglichkei- Datenbanksystem noch die Anwendung im Zugriff des Nut- ten sein. Wir nehmen weiter an, dass das Datenbanksystem zers stehen. Verdeutlicht wird dieses am Beispiel der JDBC- für den neuen Typ den >-Operator nicht mehr anbietet. Es Schnittstelle [15]. muss nun eine Vergleichsfunktion geschrieben werden, die die Aufgabe des >-Operators übernimmt. Diese tiefgreifen- 1. EINLEITUNG de Umstrukturierung scheint nun bis in die Anfrage durch, Datenbanksysteme haben in den letzten Jahrzehnten ein ist also nicht mehr transparent: breites Anwendungsspektrum erschlossen. Funktionalitäten wurden oft aufgrund der Bedürfnisse der Anwender hinzuge- Listing 2: SQL-Anfrage mit Anfrage an eine nutzer- fügt [17]. So gibt es heute nutzerdefinierte Datentypen, nut- definierte Funktion im WHERE-Teil zerdefinierte Datenablagen und selbst elementare Dinge wie Indexe, die durch einen Nutzer in ihrer Struktur bestimmt SELECT ∗ werden. FROM mitarb Allen gemein ist eine gewisse Abhängigkeit der Implemen- WHERE pruefe( mitarb.gehalt, 1000) = 1 tation vom Datenbankhersteller und einer damit verbunde- Eine Anwendung, die der Nutzer nicht verändern kann, wür- de also von diesem neuen Typ ausschließlich dann profi- tieren, wenn der Hersteller diese Möglichkeit vorsieht oder standardmäßig einbaut. Für bestehende Umgebungen ist all dies also keine Option. Im obigen Fall würde noch die Möglichkeit des automati- schen SQL-Umschreibens einen Ausweg bieten [12, 8]. Dabei wird eine materialisierte Sicht angelegt. Anschließend wird 24th GI-Workshop on Foundations of Databases (Grundlagen von Daten- banken), 29.05.2012 - 01.06.2012, Lübbenau, Germany. der Datenbank mitgeteilt, dass bestimmte Anfragen nicht so Copyright is held by the author/owner(s). gestellt werden sollen, wie sie der Anwender abgesetzt hatte, sondern in veränderter Form auf der materialisierten Sicht 2.2 Datenbanktreiber abgearbeitet werden. Das Vorgehen muss vom Datenbank- Der Datenbanktreiber ist die Schnittstelle für einen An- system aber auch unterstützt werden. Je nach Ausprägung wendungsprogrammierer, um mit dem Datenbanksystem zu müssen außerdem genaue Übereinstimmungsmerkmale an- kommunizieren. Er stellt Funktionen bereit, um Verbindun- gegeben werden, mit denen das Umschreiben ausgelöst wird. gen zu verwalten und Datenbankanfragen abzuarbeiten (sei Scheitert das Umschreiben, weil es eine kleine Varianz in der es nun SQL oder irgendeine andere Art der Anfrage) [5, Anfrage gibt, wird das Ergebnis u. U. falsch. 11]. Es ist wichtig, zu beobachten, dass dabei jeder Ab- Im Folgenden werden wir eine Möglichkeit aufzeigen, wie arbeitungsschritt von der Anwendung ausgelöst wird. Alle es ohne einen Eingriff – weder bei der Anwendung noch Ergebnisse einer Anfrage werden nicht einfach als Resultat bei der Datenbank – möglich ist, einen Index weitestgehend einer query()-Funktion zurückgegeben, sondern müssen ak- transparent in ein bestehendes System zu integrieren. Da- tiv angefordert werden. Eine typische Schrittfolge, die eine zu wird zunächst untersucht, an welchen Stellen und wie in Anwendung verwenden könnte, ist in Listing 3 aufgezeigt. die Kommunikation von Anwendung und Datenbanksystem eingegriffen werden kann. Anschließend wird auf die Heraus- forderungen eingegangen, die sich bei dem hier genutzten Listing 3: Mögliche, stark reduzierte, Schrittfolge Ansatz zeigen und wie diese gelöst werden können. bei der Nutzung einer Datenbankbibliothek, hier JDBC. Es wird zunächst eine Verbindung geöffnet, 2. INTEGRATIONSPUNKTE dann ein Statement mit ungebundenen Variablen vorbereitet und gebunden. Schließlich werden die 2.1 Überblick angefragten Daten abgeholt. Connection conn = DriverManager.getConnection( Um mögliche Integrationspunkte zu finden, muss zunächst "jdbc:mysql://localhost/testdb", untersucht werden, wie eine Anwendung mit einem Daten- "username", banksystem kommuniziert. Üblicherweise werden hierfür Da- "password"); tenbanktreiber eingesetzt. Das sind Programmbibliotheken, Statement ps = conn.prepareStatement( die die Anfragen in ein dem Datenbanksystem verständli- "SELECT ∗ FROM mitarb ches Protokoll überführen und dieses dann übermitteln. Der WHERE gehalt > ?"); Datenbankserver dekodiert das Protokoll und arbeitet die ps. setInt (1, 1000); darin enthaltenen Anweisungen ab. ResultSet rs = ps.executeQuery(); String name = rs.getString("name"); ps. close () ; conn.close () ; Wie nun stellt sich hier eine Möglichkeit zur Integration dar? Es ist möglich, vor jede Funktion, die eine Anwendung vom originalen Datenbanktreiber aufruft, eine eigene Funk- tion zu setzen. Die Anwendung ruft nun die eigene Funk- tion, ohne dies zu bemerken, und die eigene Funktion ruft schließlich die originale. Da nun alle Daten, die von einer Anwendung zum Datenbanksystem gesendet werden, vorher Abbildung 1: Schematische Darstellung des Zusam- analysiert und verändert werden können, stellt sich so dieser menspiels zwischen Anwendung und Datenbank. Die Integrationspunkt dar. Außerdem können eigene Funktionen Anwendung verwendet ein API für einen Daten- auf der so abgefangenen Datenbankverbindung „huckepack“ banktreiber, welcher vom Datenbankhersteller zur aufgesetzt werden. Verfügung gestellt wird. Dieser Treiber ist dann für Ein erster Gedanke, dies zu realisieren, könnte in die Rich- die Kommunikation mit dem Datenbanksystem über tung einer DLL-Injection [18] gehen. Das bedeutet das kom- ein Netzwerk verantwortlich. plette Ersetzen des vom Datenbankhersteller bereitgestell- ten Treibers durch einen eigenen. Dieser kann, da die Proto- Das beschriebene Szenario – abgebildet in Abbildung 1 – kolle nicht zwingend offengelegt sein müssen, die Kommuni- offenbart drei Möglichkeiten, eine Integration vorzunehmen: kation mit dem Datenbanksystem nicht selbst übernehmen, • den Datenbanktreiber, sondern ruft den ursprünglichen Datenbanktreiber. Abhän- gig von der Anzahl der zu implementierenden Funktionen • die Kommunikation über das Netzwerk und kann dies ein möglicher Weg sein. Eine weit verbreitete sol- che Schnittstelle, um aus einer Javaanwendung mit einem • das Datenbanksystem selbst. Datenbanksystem in Verbindung zu treten, ist JDBC. Mit seinen vielen Klassen und mehr als 1000 zugehörigen Me- Im Folgenden werden wir uns auf den Datenbanktreiber, al- thoden [6] wäre es eine sehr langwierige Aufgabe, einen sol- so die Anwendungsseite, konzentrieren. Die Vorgehensweise chen sogenannten Wrapper [7] zu implementieren. In einem bei der Integration in die Kommuniktion ist bereits in [1] unserer Produkte namens Cardigo ist dieses aber bereits im- beschrieben. Möglichkeiten, ein Datenbanksystem zu erwei- plementiert und erleichtert so die Aufgabe enorm. Weitere tern, wurden in den letzten Jahrzehnten vielfach an anderer Projekte und Arbeiten zu diesem Thema sind unter anderem Stelle beschrieben [4, 20, 2]. auch bei [19, 22, 21] und [13] zu finden. Cardigo ist ein Rahmenwerk, welches u. a. alle Klassen Index an das Datenbanksystem zu übertragen. Es schließt und Methoden enthält, die das JDBC-API anbietet. An- sich eine Betrachtung an, die die programmtechnische Inte- statt selbst ein kompletter Treiber zu sein, bietet es lediglich gration betrachtet, da sich hier noch einige weitere Probleme einen Wrapper für einen „richtigen“ Datenbanktreiber. Das auftun. Ziel dieses Produktes ist es, einem Anwender die Möglichkeit zu geben, die Datenbankkommunikation – in diesem Falle 3.1 Logische Integration hauptsächlich Anfragen, Ergebnisse u. s. w. – zu loggen oder Die Grundidee der Integration ist es nun, die Anfrage, die gar zu verändern. Mit diesem Werkzeug können wir nun die eine Anwendung absetzt, so zu verändern, dass sie das Ver- Integration des Index angehen. halten eines datenbankinternen Index nachahmt. Die Anfra- Technisch ist zur Integration von Cardigo nichts weiter ge aus Listing 1 könnte nun, wie in Listing 4 aufgezeigt, um nötig, als ein geänderter Verbindungsparameter für die An- das Primärschlüsselattribut erweitert werden. wendung. Dieser bewirkt, dass anstelle des originalen JDBC- Treibers nun Cardigo geladen wird. Der Aufbau dieser ver- änderten Umgebung ist in Abbildung 2 verdeutlicht. Listing 4: SQL-Anfrage, die um die Ergebnisse eines externen Index erweitert wurde SELECT ∗ FROM mitarb WHERE gehalt > 2000 AND id IN (4, 18) Dieses Vorgehen vertraut darauf, dass der Optimierer des Datenbanksystems erkennt, dass es sich bei den Werten in der IN-Klausel um Primärschlüssel handelt. Er muss diese möglichst am Anfang der Anfrageverarbeitung einbeziehen, um die Menge der zu untersuchenden Tupel zu minimieren. Durch Tests haben wir herausgefunden, dass die Anzahl der in IN-Listen enthaltenen Elemente eine Obergrenze hat. Durch die Disjunktion mehrerer IN-Listen kann diese zu ei- nem gewissen Grad ausgeglichen werden. Somit ist es mög- lich, sehr lange Anfragen zu erzeugen, Allerdings gibt es auch eine Grenze für die maximale, vom Datenbanksystem zuge- lassene, Anfragelänge. Bei IBM DB2 und Oracle ist diese Maximallänge bspw. 64kB [8, 16]. Ein weiterer Aspekt, der bei diesen langen Anfragen be- trachtet werden muss, ist, dass diese vom Datenbanksystem auch geparst werden. Werden die Anfragen lang, so stei- Abbildung 2: Anwendung, die Cardigo durch einen gen auch deren Parsezeiten, selbst optimistisch betrachtet veränderten Kommunikationsparameter nutzt. Der ist dieser Zusammenhang linear. Auch systematisch bedingt, Code, den ein Nutzer schreibt, umfasst typischer- ist, dass der Optimierer zu lange und viele IN-Listen nicht weise nicht den gesamten API-Umfang von JDBC, beachtet, selbst wenn es sich um Primärschlüssel handelt. weshalb er hier nicht über die gesamte Breite dar- Mit Hinweisen an den Optimierer kann hier gegengesteuert gestellt ist. Exemplarisch sind die in Listing 3 ver- werden. Zusammenfassend lässt sich aber sagen, dass ab ei- wendeten Methoden dargestellt. ner gewissen Anfragelänge, der Gewinn durch den Index sich im schlechtesten Falle sogar ins Gegenteil verkehren kann. Um diese Beschränkungen zu umgehen, können die Er- gebnisse des Index auch in eine Tabelle in der Datenbank 3. INTEGRATION eingefügt werden. Hier gibt es wieder mehrere Möglichkei- Bevor wir die Integration des Index weiter betrachten, wol- ten: len wir kurz darauf eingehen, wie ein in ein Datenbanksys- tem integrierter Index arbeitet: Wird eine Anfrage an die 1. Einfügen in eine Tabelle, die angelegt ist Datenbank gestellt und treffen einige der verwendeten At- 2. Einfügen in eine temporäre Tabelle tribute die im Index enthaltenen, so wird der Index verwen- det. Dabei wird die Anfrage vom Index bearbeitet und im In beiden Fällen muss allerdings die Datenbank in der Wei- Ergebnis entsteht einen Liste von Ergebniskandidaten. Die- se modifiziert werden, dass die Anwendung, in die der In- se können in Form von RowIDs [3] oder auch einfach als dex integriert wurde, das Recht hat, auf diese Tabellen zu Primärschlüssel vorliegen. Das Datenbanksystem überprüft schreiben. Die Tabellen müssen prinzipiell eine Spalte für dann nur noch die Datensätze, deren Identifikatoren der In- die Anfrage und eine Spalte für die Ergebnisse des Index dex als Ergebnis lieferte. Auf diese Art wird der Aufwand, besitzen. den das Datenbanksystem beim Laden der Datensätze und Werden über eine Sitzung Anfragen nur sequenziell be- ihrer Verifikation hat, erheblich verringert [10]. arbeitet, haben temporäre Tabellen den Vorteil, dass zwi- Im Folgenden wird zunächst die logische Integration be- schen verschiedenen Datenbanksitzungen nicht mittels der trachtet, d. h., wie es überhaupt möglich ist, Ergebnisse eines eben beschriebenen zusätzlichen AnfrageID-Spalte in dieser Tabelle unterschieden werden muss. Das ist darin begrün- 4. ERGEBNISSE UND AUSBLICK det, dass temporäre Tabellen für jede Sitzung als leere neue Das hier beschriebene System war bereits erfolgreich im Ein- Tabellen erscheinen. Die Aktionen einer Sitzung wirken sich satz. Die Latenzen für das reine Abfangen der Datenban- nicht auf den Inhalt der temporären Tabelle in einer anderen kaufrufe bewegen sich im einstelligen Mikrosekundenbereich, Sitzung aus. also dem, was für einen Funktionsaufruf erwartet werden Ein bisher nicht zur Sprache gekommener Punkt ist das kann. Hinzu kommt die Zeit für die Indexanfrage. Für einen Aktualisieren des Index. Natürlich muss ein datenbankexter- realen Gewinn muss natürlich die Zeit für die Integrati- ner Index über INSERT-, UPDATE- und DELETE-Operationen on, die Indexanfrage und den Einbau der Ergebnisse in das informiert werden. Der einfachste Weg ist, wenn alle Ope- Statement in Summe geringer sein, als die einer Anfrage oh- rationen, die auf der Datenbank laufen, über die gleiche ab- ne den externen Index. gefangene Schnittstelle gehen und so direkt gelesen werden Es zeigte sich auch, dass, wird eine Integration über Ta- können. In der Realität ist dies jedoch unpraktisch, da die- bellen angestrebt, es verschiedene Arten gibt, die Ergebnisse se Voraussetzung nicht zu 100% gewährleistet werden kann. aus der Ergebnistabelle zu entfernen. In 3.1 wurden die ver- Trigger sind eine Variante, wie Veränderungen in der Daten- schiedenen Arten von Tabellen hierfür beschrieben. Wenn bank nach außen gereicht werden können, diese müssen je- keine Spalte für die AnfrageID verwendet werden muss, so doch integriert werden dürfen. Hier ergeben sich damit auch können die Ergebnisse mit einem TRUNCATE entfernt werden. Grenzen, über die hinaus unser Ansatz nicht angewendet Dieses wird erheblich schneller ausgeführt, als ein DELETE werden kann. Eine andere Möglichkeit sind statische Daten- FROM ... WHERE anfrage_id ==. haltungen, die nur in definierten Zeitabschnitten aktualisiert Unsere weitere Arbeit beschränkt sich nicht nur auf eine werden, bspw. einmal pro Monat. Hier kann ein statischer Integration in JDBC, die wir hier aufgezeigt haben, sondern Index genutzt werden, der über eine simple Zeitsteuerung geht auch darüberhinaus auf native Datenbanktreiber ein, aktualisiert wird. die dann jedoch herstellerspezifisch sind. Hier müssen andere Mechanismen angewandt werden, eine Integration elegant zu 3.2 Programmtechnische Integration vollziehen, die Prinzipien bleiben jedoch die gleichen. Auch Oft halten sich Anwendungsprogrammierer an die Beispiele der bereits vorgestellte Ansatz, einen Proxy zu integrieren, der Autoren der jeweiligen Datenbankschnittstelle. Jedoch der das Protokoll, welches das Datenbanksystem im Netz- erlauben alle APIs auch eine freiere Nutzung, d. h., dass die werk verwendet, versteht, wurde weitergeführt und zeigte Schrittfolge der Kommandos nicht festgelegt ist und es ver- sich bereits im Einsatz als wertvolle Hilfe. Das oben bereits schiedene Gründe geben kann, die so aufgezeigten Standar- erwähnte Cardigo dient uns dabei als Werkzeugkasten, der droutinen zu verwerfen. Listing 3 zeigt zunächst einen Stan- alle diese Möglichkeiten vereint. dardweg auf. Für diesen wollen wir nun die Schritte, die ein datenbankexterner Index verfolgen kann, aufzeigen: • Statement vorbereiten (conn.prepareStatement(...)): if Anfrage relevant then Anfrage speichern end if • Variablen binden (ps.setInt(...)): if Anfrage war relevant then Bindung speichern end if • Statement ausführen (ps.executeQuery()): if Anfrage war relevant then Index anfragen Indexergebnisse in DB laden Anfrage modifizieren Datenbank anfragen end if • Ergebnisse holen (rs.getString(...)): hier sind keine weiteren Schritte notwendig Beobachtungen an realen Programmen zeigen, dass das Binden von Variablen teils mehrfach auf die gleichen Varia- blen angewendet wird. Mit dem eben beschriebenen Verfah- ren ist dies kein Problem. Auch Operationen, die ein State- ment näher beschreiben, sind nach wie vor ausführbar, da alle Bestandteile erhalten bleiben und nur Ergänzungen vor- genommen werden. 5. LITERATUR example and in detail, IBM Developer works DB2 library. Dec. 2003. [1] A. Adam, S. Leuoth, and W. Benn. Nutzung von [21] Thedwick, LLC. jdbcgrabber. http://code.google. Proxys zur Ergänzung von Datenbankfunktionen. In com/p/jdbcgrabber/. W.-T. Balke and C. Lofi, editors, Grundlagen von [22] C. Wege. Steps out of Integration Hell - Protocol Datenbanken, volume 581 of CEUR Workshop Interception Wrapper. In A. Rüping, J. Eckstein, and Proceedings. CEUR-WS.org, 2010. C. Schwanninger, editors, EuroPLoP, pages 455–458. [2] E. Belden, T. Chorma, D. Das, Y. Hu, S. Kotsovolos, UVK - Universitaetsverlag Konstanz, 2001. G. Lee, R. Leyderman, S. Mavris, V. Moore, M. Morsi, C. Murray, D. Raphaely, H. Slattery, S. Sundara, and A. Yoaz. Oracle Database Data Cartridge Developers Guide, 11g Release 2 (11.2). Oracle, July 2009. [3] P. Bruni, F. Bortoletto, R. Kalyanasundaram, G. McGeoch, R. Miller, C. Molaro, Y. Ohmori, and M. Parbs. DB2 10 for z/OS Performance Topics. IBM Form Number SG24-7942-00, IBM Redbooks, June 2011. [4] Desloch et al. PatNr. US 6,338,056 B1 – Relational Database Extender that Supports User-Defined Index Types and User-Defined Search, Apr. 1999. [5] R. Elmasri and S. B. Navathe. Grundlagen von Datenbanksystemen (3. Aufl., Bachelorausgabe). Pearson Studium, 2009. [6] M. Fisher, J. Ellis, and J. C. Bruce. JDBC API Tutorial and Reference. Pearson Education, 3 edition, 2003. [7] E. Gamma, R. Helm, R. Johnson, and J. Vlissides. Design Patterns. Addison-Wesley, Boston, MA, January 1995. [8] IBM. SQL Reference, Volume 1. IBM Corporation, Nov. 2009. [9] IBM Deutschland GmbH. DB2 Spatial Extender und Geodetic Data Management Feature – Benutzer- und Referenzhandbuch, July 2006. [10] T. Lahdenmäki and M. Leach. Relational database index design and the optimizers: DB2, Oracle, SQL server, et al. Wiley-Interscience, 2005. [11] T. Langner and D. Reiberg. J2EE und JBoss: Grundlagen und Profiwissen ; verteilte Enterprise-Applikationen auf Basis von J2EE, JBoss & Eclipse. Hanser, 2006. [12] D. Lorentz and M. B. Roeser. Oracle Database SQL Language Reference, 11g Release 2 (11.2). Oracle, Oct. 2009. [13] A. Martin and J. Goke. P6spy. http://sourceforge. net/projects/p6spy/. [14] C. Murray. Oracle Spatial Developers Guide, 11g Release 2 (11.2). Oracle, Dec. 2009. [15] G. Reese. Database Programming with JDBC and Java, Second Edition. O’Reilly & Associates, Inc., Sebastopol, CA, USA, 2nd edition, 2000. [16] B. Rich. Oracle Database Reference, 11g Release 2 (11.2), Sept. 2011. [17] G. Saake, K.-U. Sattler, and A. Heuer. Datenbanken: Konzepte und Sprachen, 3. Auflage. mitp-Verlag, Redline GmbH, 2008. [18] J. Shewmaker. Analyzing dll injection, 2006. GSM Presentation, Bluenotch. [19] M. Smedberg. Boilerplate JDBC Wrapper. http:// blog.redfin.com/devblog/2011/03/boilerplate_ jdbc_wrapper.html. [20] K. Stolze and T. Steinbach. DB2 Index Extensions by