Datenbank – Sebastians Blog https://sgaul.de Neues aus den Softwareminen Mon, 21 Sep 2015 09:38:43 +0000 de-DE hourly 1 https://wordpress.org/?v=6.1.1 https://sgaul.de/wp-content/uploads/2019/02/cropped-sgaul-2-1-32x32.jpg Datenbank – Sebastians Blog https://sgaul.de 32 32 Idee für DB2CSV2DB https://sgaul.de/2015/09/12/idee-fuer-db2csv2db/ Sat, 12 Sep 2015 10:40:15 +0000 https://sgaul.de/?p=2779 Idee für DB2CSV2DB weiterlesen]]> Egal welch schöne Verwaltungsoberflächen man strickt, manchmal ist es einfach angenehmer den Datenbankinhalt in den Editor zu schieben, dort zu Suchen und Ersetzen und das Ergebnis wieder in die Datenbank zu schieben. Ich denke da an einen einfachen Query-Generator, der die Tabelle als CSV in einer Textarea ausgibt und diese direkt als Update akzeptiert:

db2csv2db

Ich denke mir den Spaß als Rails-Engine, welche die Grundfunktionalität von Active-Record nutzt, ohne aber mit Models zu arbeiten. Keine Validierung, keine Callbacks. Nur direkte Datenbankmanipulation.

Ausgehend von der ActiveRecord::Base.connection kann man direkt die mit Rails verbundene Datenbank ansprechen. Es lässt sich beliebiges SQL ausführen oder man kann diverse High-Level-Methoden der API nutzen.

Der Weg von der Datenbank in das CSV-Format sollte mit Rails vergleichsweise einfach sein. Interessanter erscheint mir das anschließende Update: Machen hier verschiedene Datentypen Probleme? Wie findet man den korrekten Datensatz bei mehrspaltigen Primärschlüsseln?

]]>
Von Data-Warehouses und Website-Statistiken https://sgaul.de/2013/06/09/von-data-warehouses-und-website-statistiken/ https://sgaul.de/2013/06/09/von-data-warehouses-und-website-statistiken/#comments Sun, 09 Jun 2013 13:26:42 +0000 https://sgaul.de/?p=2201 Von Data-Warehouses und Website-Statistiken weiterlesen]]> Schon vor längerer Zeit habe ich im Rahmen meiner damaligen Firma ein Analysewerkzeug für Website-Besuche geschrieben. Leider ist das ganze recht organisch gewachsen, so dass es heute schwer fällt die Software zu verbessern. Wie lässt sich eine belastbare Architektur entwickeln? Ein Stichwort, an dass ich im Zusammenhang mit großen Datenmengen stets denken muss: Data-Warehouses.
Zugriffsstatistiken werden immer wichtiger
Die Farbwahl für Diagramme ist eine Wissenschaft für sich…

Data-Warehouse: Datenintegration und -separation

Ein Data-Warehouse ist eine Datenbank, die zwei grundlegende Ziele verfolgt:

  1. Datenintegration aus heterogenen Quellen
  2. Separation der Daten; das Data-Warehouse hat keinen Einfluss auf die operativen Daten

Datenintegration

Beide Aspekte sind für Website-Statistiken höchst relevant. Viele Web-Server stellen mehrere Websites mit unterschiedlichen Technologien bereit. Selbst wenn nicht, möchte ich als Admin die Möglichkeit haben, meinen Apache gegen ein Nginx oder mein Typo 3 gegen ein WordPress auszutauschen. Heterogene Quellen, in welchen die Daten auflaufen, sind somit zumindest potentiell immer gegeben. Ein weiterer Vorteil: Bin ich auf kein festes Format angewiesen, kann ich auch immer die nativen Mechanismen der verwendeten Software nutzen. Apache, Nginx und Co. loggen ohnehin jeden Besucher mit, eine zusätzliche Erfassung der Daten (wie zum Beispiel durch Piwik) ist oft gar nicht nötig. Ein Data-Warehouse kann diese selbstständig integrieren.

Datenseparation

Auch Punkt 2 ist wie fürs Web gemacht: Statistiken sind sicher wichtig, aber nie so, dass sie das eigentliche Webangebot behindern dürften. Ist der Server bereits ausgelastet, so kann ein Aufruf der Statistiken mit unzähligen Leseoperationen und Berechnungen zum großen Problem werden. Spätestes wenn der Speicher voll ist gehen bei kleinen Projekten wie diesem Blog die Lichter aus. Das Prinzip der Datenseparation bietet hier Abhilfe: Die Statistiken werden vollständig von den operativen Daten getrennt. Das Data-Warehouse kann bei Bedarf auf einem anderen Server liegen.

Hierfür müssen die operativen Daten zwar ebenfalls gelesen werden, dies kann in hohen Lastphasen aber einfach unterbunden werden. Der Webserver kann sich auf seinen eigentlichen Job konzentrieren und auch der Statistikaufrufer kriegt schnell und optimiert seine Zahlen. Lediglich Letzterer hat hierbei den Nachteil, dass die Daten nicht mehr ganz in Echtzeit bereitstehen – was wohl zu verkraften sein dürfte. Das Internet ist zwar schnelllebig, die Zugriffe von vor fünf Minuten sind für die meisten aber aktuell genug.

Nachteile

Der Data-Warehouse-Ansatz für die Website-Zugriffsanalyse birgt kaum Probleme. Zwei drängen sich zunächst auf:

  • Keine Echtzeitdaten
  • Erhöhter Speicherverbrauch durch Datenduplizierung

In meinen Augen sind beide Nachteile unkritisch. Die Aktualitätsspanne zwischen Echtzeit- und Data-Warehouse-Daten lässt sich je nach Kapazität beliebig verkleinern. Je öfter die Daten integriert werden, desto weniger Neuerungen sind zu verarbeiten. Selbst minütliche Syncs sind realistisch, wenn man seine Zugriffsspitzen im Blick hat und nach Bedarf das Intervall anpasst.

Der vermehrte Speicherverbrauch war selbst zu Zeiten der Festplattenkrise kein Problem. Wer jeden Tag gigabyteweise Zugriffsdaten wegschreibt hat sicher andere Sorgen als zehn Festplatten im Jahr…

Skalierbarkeit und Datenstrukturkonzeption

Das Konzept Data-Warehouse ist simpel und überzeugend. Für Website-Statistiken überzeugt vor allem die Skalierbarkeit: Vom kleinen PHP-Webspace mit My-SQL-Datenbank kann eine gut konzipierte Datensammlung mitwachsen und auf beliebig große und verteilte Systeme migriert werden.

Zudem bietet dieses Forschungsfeld interessante Ansätze, wie man Daten effizient an das Anwendungsfeld angepasst strukturiert. OLAP-Cubes und Sternschemas für relationale Datenbanken sind wichtige Stichwörter, die jedoch einen eigenen Artikel rechtfertigen.

]]>
https://sgaul.de/2013/06/09/von-data-warehouses-und-website-statistiken/feed/ 4
SQL-Datenbankänderungen testen https://sgaul.de/2013/04/14/sql-datenbankanderungen-testen/ Sun, 14 Apr 2013 16:53:11 +0000 https://sgaul.de/?p=2128 SQL-Datenbankänderungen testen weiterlesen]]> Manchmal dauert es ein wenig, bis man auf das Offensichtliche kommt. Ich habe hin und her überlegt, wie ich ein Update und Alter Table testen kann, ohne die Daten zu gefährden. Die Lösung ist elementarer Bestandteil einer jeden SQL-Datenbank: Eine Transaktion.

Transaktionen in PostgreSQL

begin;
alter table mytable rename column id to name;
\d mytable

         Table "public.mytable"
   Column   |   Type     |   Modifiers   
------------+------------+--------------
 name       | bigint     | not null
rollback;
\d
         Table "public.mytable"
   Column   |   Type     |   Modifiers   
------------+------------+--------------
 id         | bigint     | not null

Sind die vorgenommenen Änderungen korrekt, können sie mit commit; übernommen werden. Der offizielle SQL-Befehl zum Starten einer Transaktion ist start transaction;. Allerdings unterstützen alle mir bekannten Datenbanken die etwas handlichere Form begin;.

Verschachtelte Transaktionen: Savepoints

Ist der Test komplexer, so dass man Transaktionen schachteln möchte, kann man sogenannte Savepoints verwenden.

begin;
-- Änderung 1
savepoint sp1;
-- Änderung 2a
rollback to savepoint sp1; -- 2a zurücknehmen
-- Änderung 2b
rollback; -- 2b und 1 zurücknehmen

Transaktionen in MySQL

Die PostgreSQL-Beispiele werden auch von MySQL unterstützt.

]]>
Probleme mit falschen Liquibase-Checksummen beheben https://sgaul.de/2013/01/09/probleme-mit-falschen-liquibase-checksummen-beheben/ https://sgaul.de/2013/01/09/probleme-mit-falschen-liquibase-checksummen-beheben/#comments Wed, 09 Jan 2013 19:15:35 +0000 https://sgaul.de/?p=1866 Probleme mit falschen Liquibase-Checksummen beheben weiterlesen]]> Liquibase ist eine nette Sache, um die Evolution von Datenbankschemata zu verwalten. Nervig wird es, wenn man während der Entwicklung ein bereits ausgeführtes Changeset noch einmal ändern muss und infolge dessen die Checksummen nicht mehr stimmen:

liquibase.exception.ValidationFailedException: Validation Failed:
1 change sets check sum
changelog.xml::changeSetId::author is now: 3:eeeedcadbc71ae018f46bd682e9132c7

Die Lösung ist recht einfach: Der betroffene Hashwert kann aus der Changelog-Tabelle von Liquibase entfernt werden:

update databasechangelog set md5sum = null where id = 'changeSetId';

Beim nächsten Update wird nun der korrekte Wert nachgetragen, ohne dass die zugehörigen Änderungsanweisungen erneut ausgeführt werden:

Updating null or out of date checksum on changeSet etc/db/changelog.xml::changeSetId::author::(Checksum: 3:...) to correct value
]]>
https://sgaul.de/2013/01/09/probleme-mit-falschen-liquibase-checksummen-beheben/feed/ 1
Referenzen bei Problemen mit großen Datenmengen https://sgaul.de/2012/04/21/referenzen-bei-problemen-mit-grosen-datenmengen/ Sat, 21 Apr 2012 11:21:58 +0000 https://sgaul.de/?p=1141 In einem größeren PHP-Projekt hatte ich kürzlich das Problem, dass große Teile der Datenbanken in Arrays geschoben wurden um von dort aus weiterverarbeitet zu werden. Dies ist generell kein schöner Ansatz, war in der besagten Situation aber nicht mehr zu ändern. Ein Kollege kam auf die rettende Idee, die ich hier kurz notieren möchte, so dass ich sie nicht vergesse.

Der Speicherfresser: Array zurückgeben

function getAllTableRows() {
  // ...
  return $allRows;
}
$allRows = getAllTableRows();

Dieser Ansatz führte nun leider regelmäßig dazu, dass PHP mit einer Speicherfehlermeldung abbrach.

Der sparsame Ansatz: Array als Referenzparameter

function getAllTableRows(&$allRows) {
  // alle Werte in $allRows schreiben
}
$allRows = array();
getAllTableRows($allRows);

Fast schon traurig, dass das für PHP so einen Unterschied macht. Ich vermute, dass das an PHPs Eigenheit liegt, mehr auf Werten als auf Referenzen zu arbeiten. Ironischerweise behauptet das PHP-Manual an ähnlicher Stelle, der Kern sei intelligent genug, dies selbst zu optimieren, zumindest was Rückgaben angeht.

Mangels ausreichend großer Beispiel konnte ich den folgenden Ansatz nicht testen:

function &getAllTableRows() {
  // ...
  return $allRows;
}
$allRows =& getAllTableRows();
]]>
Große Datenmengen mit Extbase verarbeiten https://sgaul.de/2011/11/17/grose-datenmengen-mit-extbase-verarbeiten/ https://sgaul.de/2011/11/17/grose-datenmengen-mit-extbase-verarbeiten/#comments Thu, 17 Nov 2011 16:21:04 +0000 https://sgaul.de/?p=728 Extbase ist an sich eine schöne Sache: Man kann mit relativ geringem Aufwand auch komplexe Anwendungen schreiben. Ein großes Problem ist jedoch die Effizienz. Das vollständige Auslesen von Objekten aus einer Datenbank in ein Array, um diese nachfolgend zu bearbeiten, ist speicherintensiv und merklich langsam. Möchte man einfach eine lange Liste an Logs ausgeben, fällt das besonders auf. Ich möchte hier einen eleganten Weg zeigen, wie man möglichst direkt jede Datenbankzeile in die Ausgabe schreibt.

Das Ziel

Wir möchten eine Liste von Logs im Browser anzeigen. Da Sortierung und Seiteneinteilung von Javascript übernommen werden, möchten wir direkt 1000 Zeilen der Datenbanktabelle in die HTML-Tabelle übertragen. Die Tabelle soll dabei möglichst schnell ausgeliefert werden.

Der Ablaufplan


  
    
    
    
      
    
    
      
    
    
      
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
      
      
    
    
      
      
    
    
      
      
    
    
      
      
    
    
      
      
    
    
      
      
    
    
      
      
    
    
      
      
    
    
      
      
    
    
      
      
    
    
      
      
    
    
  
  
  
    
      
        image/svg+xml
        
        
      
    
  
  
    
    Controller
    
    Fluid-Template
    
    ViewHelper
    
    IteratorRepository
    
    
    Table Data
    
    1
    
    2
    
    4
    
    5
    
      
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    
    
    
    
    
    
    Table Row
    
    next()
    
    3
  

Nichts zu sehen? Zur PNG-Version.

Hinweis: Die Darstellung ist nicht ganz korrekt, da der Controller die gerenderten Daten des Templates zurückbekommt und diese in Richtung Ausgabe weiterleitet. Vielen Dank an Alex für diesen Hinweis.

Der Controller

Der Controller verliert in diesem Ansatz die Aufgabe, irgendwelche Daten für die Log-Tabelle zu besorgen. Er muss lediglich das entsprechende Template aufrufen und ggf. andere Jobs erledigen, die neben der Tabelle auf der Seite zu sehen sind.

Das Fluid-Template

Das Template gestaltet das Drum-Herum und ruft darin für die Log-Tabelle einen View-Helper auf. Zudem kann man als Inhalt des View-Helper-Tags ein Template vorgeben, in welchem der Helper nur Variablen ersetzen braucht. Hierfür muss man den allgemeinen Teil von dem trennen, der mit jeder Zeile wiederholt werden muss. Ein simpler Ansatz wäre etwa:


	
			
IDInhalt
%1$d%1$s

Das obige Variablenformat lässt sich dann direkt mit PHPs Sprintf-Funktion befüllen.

Der View-Helper

Dies ist die einzige Stelle, an der wie die kompletten Log-Daten zwischenspeichern. Dafür aber gleich im fertigen Ausgabeformat, so dass wir sie nicht noch einmal durcharbeiten müssen. Hierfür nehmen wir eine Singleton-Instanz des Iterator-Repositorys, iterieren über die einzelnen Zeilen der Datenbanktabelle und befüllen hiermit jeweils unser Template. Am Ende geben wir den so zusammengebauten Ausgabestring zurück.

Das Iterator-Repository

Das Repository implementiert das PHP-Iterator-Interface. Dies erlaubt es dem View-Helper, das Repository in einer Foreach-Schleife auszulesen. Der Rest ist relativ simpel: Beim Aufruf von rewind() und dem Konstruktor wird ein Query abgesetzt, das Result speichern wir in einem Klassenattribut, um es in anderen Methoden nutzen zu können.

$this->result = $GLOBALS['TYPO3_DB']->SELECTquery(/*...*/);

Hierbei sollte gleich darauf geachtet werden, dass möglichst viel Logik direkt in SQL erledigt wird. So kann man beispielsweise Datumsformate direkt im Query definieren.
Ein Aufruf von next() setzt ein Row-Attribut mittels

$this->row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($this->result);

Zu guter Letzt muss ein current() noch $this->row oder eine angepasste Variante davon zurückgeben.

Fazit

Die vorgegebenen Code-Schnipsel dienen der Verdeutlichung und sind nicht vollständig. Wenn man dem Ansatz jedoch folgt, kann man sehr direkt auf der Datenbank arbeiten, ohne die offizielle Vorgehensweise von Extbase wirklich zu verletzen.

]]>
https://sgaul.de/2011/11/17/grose-datenmengen-mit-extbase-verarbeiten/feed/ 6