Archiv des Autors: Sascha Presnac

Rezension: SQL Performance Explained

SQL_Performance_Explained_cover_deutsch_hires[1]

SQL Performance Explained Cover

Bemessen an der Seitenzahl ist das Buch „SQL Performance Explained“ von Markus Winand eher ein dünnes und verliert sich damit in der Reihe der dicken Wälzer im (Fach-)Bücherregal. Lass dich aber von diesem Umstand nicht täuschen. Für „SQL Performance Explained“ kann man locker 2 oder 3 dicke Wälzer wegwerfen.

Dabei lernst du eigentlich nur etwas über einen kleinen Teil von Datenbanken, der sich aber dafür umso mehr bemerkbar macht: Der Index.

Markus erklärt sehr gut und sehr anschaulich, wie so ein Index aussieht, wie er funktioniert und was er bringt – Performance nämlich und das nicht zu knapp. Auf 207 Seiten (mir liegt das PDF vor) erklärt Markus sehr praxisnah und verständlich, vernachlässigt aber auch nicht die Theorie, die einer Datenbank zugrunde liegt.

Du hattest sicherlich Datenbanktheorie im Studium und kannst dich noch stöhnend an die vielen Vorlesungen erinnern, die damit einhergingen. „SQL Performance Explained“ schafft es, bezogen auf die Kernaussage „Performance“, alles in einem übersichtlichen Werk zusammen zu fassen.

Was ich persönlich direkt aus dem Buch in meiner täglichen Arbeit umsetzen konnte kam in Kapitel 2 „Die Where-Klausel“ und zwar war dies die Erklärung der „Zusammengesetzten Schlüssel“. Die Erklärung war einfach und merkbar und so konnte ich schon in mehreren Projekten davon profitieren. So lobe ich mir ein Fachbuch.

„SQL Performance Explained“ ist kein MySQL-Buch. Es ist ein Buch über Datenbanken im Allgemeinen, beinhaltet aber Beispiele u.a. für MySQL oder Oracle oder MS-SQL Server.
Falls ein bestimmtes Beispiel für eine Datenbank nicht funktioniert, weil die Datenbank diesen Befehl nicht unterstützt, dann schreibt Markus das auch gern mit in den Text. Lobenswert!

Insgesamt ein Buch, welches ich uneingeschränkt weiterempfehlen kann und werde. Ich persönlich kann es mir nicht mehr von meinem Desktop wegdenken.

Du bekommst das Buch wahlweise als Print oder PDF oder beides unter sql-performance-explained.de

Großes Lob und danke für’s schreiben, Markus!

Virtuelle Laufwerke unter Windows

Seit Windows XP gibt es die Möglichkeit virtuelle Laufwerke anzulegen. Ein virtuelles Laufwerk dient dazu, einen langen, komplizierten Dateipfad zu verkürzen, damit du damit z.B. besser via Konsole arbeiten kannst.

Ein Beispiel, deine Webseiten liegen im htdocs deines Webservers, dieser liegt im Programme Ordner:

C:\Programme\Apache2\htdocs

Per Konsole sehr umständlich zu erreichen, da du entweder immer wieder diesen Pfad eintippst oder dir eine Batchdatei mit entsprechedem Sprungbefehl baust.
Viel einfacher wäre es doch, einfach nur W: (wie Webseiten) einzutippen und schon bist du im htdocs Verzeichnis.

Das geht ganz einfach. Konsole auf und dort

subst w: c:\Programme\Apache2\htdocs

eingeben und fertig.
Nun steht dir mit einem simplen w: deine Webseiten zur Verfügung und du kannst W als ganz normales Laufwerk benutzen, z.B. auch aus deiner IDE heraus.

Falls du die Verknüpfung mal nicht mehr brauchst:

subst w: /d

und weg ist das Laufwerk wieder. Keine Angst, den Originalen Inhalten passiert dabei natürlich nichts, nur das virtuelle Laufwerk wird entfernt.

Am besten, du schreibst eine Batch-Datei und legst diese dann in den „Autostart“, dann wird das virtuelle Laufwerk bei jedem Start automatisch erstellt und steht zur Verfügung.

Mehr über subst findest du im TechNet von Microsoft unter diesem Link: http://technet.microsoft.com/en-us/library/bb491006.aspx
Dort findest du auch die Kommandos, die bei einem mit subst erstellten Laufwerk nicht funktionieren (z.B. format oder chkdsk).

Viel Erfolg!

Zend Framework, Windows und das Model

Wer unter Windows entwickelt hat es oft nicht leicht, obwohl es eigentlich unter Windows alles leichter sein sollte. Aber gerade diese „alles ist leichter“ Sachen machen es einem Entwickler manchmal schwer. Schwer, den Fehler zu finden.

Beim Zend Framework (v1.x) hat man gewisse Namenskonventionen einzuhalten. Ist einfach so. Eine dieser Konventionen betrifft die Möglichkeit, Klassen automatisch zu laden. Dazu müssen diese einem bestimmten Namensmuster folgen und in einem bestimmten Verzeichnis liegen. Der Entwickler spart sich dann das lästige „require…„. Nettes Feature.

Unter Windows aber bitte aufpassen!
Schnell kommt es zu einem „Fatal Error„, weil die Datei nicht gefunden werden konnte, obwohl diese eigentlich im richtigen Verzeichnis liegt. Und im lokalen Development-System funktioniert doch alles. Server kaputt? Mitnichten!

Aufbasse: Unter Windows ist es völlig egal, welchen „case“ die Verzeichnisse und Dateinamen haben. Ein Verzeichnis „model“ ist für Windows das gleiche wie ein Verzeichnis „Model„. Das ZF würde in einem Windows-Server in beiden Fällen problemlos dein Model finden (mal vorausgesetzt, der Rest entspricht den Namenskonventionen), ein Linux-Server (und das ist der Normalfall) findet bei „model“ dein Model aber eben nicht.

Lösung: Nenn das VZ „Model„, lösch das alte VZ „model“ auf dem Server und achte nächstes Mal gut darauf. Vor allem du, Sascha 😉

Von phpUnit zu Codeception wechseln

Codeception-LogoWenn du vom klassischen phpUnit zu Codeception wechseln möchtest, musst du erschreckend wenige Sachen beachten. Dafür bekommst du am Ende dann die vielen Vorteile von Codeception. Ob sich das für dich und dein Projekt lohnt, musst du latürnich (sic!) selbst für dich und dein Projekt entscheiden. Mir fiel die Wahl leicht…

Wie ich schon sagte, es braucht erschreckend wenig, damit Codeception die Tests übernimmt, da sich der „unit“ Teil nicht sooo stark von phpUnit unterscheidet. Ganz im Gegenteil ruft Codeception auch phpUnit unter der Haube auf. Du hast nur den Vorteil einer einheitlichen Test-Strategie und -Sprache und musst nicht eine Vielzahl von Dialekten behalten (phpUnit, Selenium, wtf, …).

Ich nehme mal an, dass deine unit-tests bereits funktionieren und dass diese im verzeichnis „tests“ liegen. Falls nicht, das „tests“ Verzeichnis solltest du schnell mal anlegen und deine Tests von dort aus starten 😉 Dann wird’s leichter.

Also los, die ersten Erfolge sind schnell gemacht:

  • Codeception „installieren“
    Sprich, die „codecept.phar“ ins root deines Projektes kopieren.
  • Per Konsole (phpStorm hat die ja eingebaut, sehr praktisch)
    „php codecept.phar bootstrap“
    Nun werden Grundlegende Sachen im Verzeichnis „tests“ angelegt.
  • Kopiere deine alten tests mit einer Sinnvollen Verzeichnisstruktur in das Verzeichnis „tests/unit“
  • benötigte Datenbank-Dumps kommen erstmal in „tests/_data/dump.sql“
  • Deine „tests/unit.suite.yml“ sollte in etwa so aussehen:
    class_name: CodeGuy
    modules:
     enabled: [Unit, CodeHelper, Db]
     config:
      Db:
       populate: true
       cleanup: false
  • In der „codecept.yml“ trägst du die Datenbankzugangsdaten für die tests ein, dann brauchst du die nicht in der „unit.suite.yml“ eintragen und die gelten somit codeception-weit, was später die Function- und Acceptance-Tests vereinfacht.
  • In deinen Tests musst du nun noch folgende Anpassungen machen, damit alles reibungslos funktioniert:
    • Die Testdatei fängt immer mit
      use Codeception\Util\Stub;

      an.

    • Die Tests erweitern nun
      \Codeception\TestCase\Test

      also

      class myWhateverTest extends \Codeception\TestCase\Test {
       // ...
      }
    • Die Methoden „setUp()“ und „tearDown()“ werden zu „_before()“ und „_after()“. Denkt auch an den Aufruf parent::_before() und parent::_after() in den Methoden!
  • Eure bisherige „bootstrap.php“ muss in „tests/_bootstrap.php“ oder ihr passt die „codecept.yml“ einfach an.

Damit steht nun das Grundgerüst und ihr könnt via

php codecept.phar run

eure Tests ausführen.

In meinem konkreten Fall konnte ich damit die Tests einer ZF1 Application mit Anlegen und Füllen einer Testdatenbank (MySQL) um den Faktor 8 beschleunigen. Zusätzlich kann nun recht einfach neue Tests in Codeception einfügen und die Ergebnisse stehen mir ebenfalls für Jenkins und Co zur Verfügung, teilweise mit sehr viel höherer Aussagekraft.

Viel Erfolg…

Sonderzeichen im UTF-8 CSV Export für Excel

Wer schon mal CSV Daten geschrieben hat kennt sicher das Problem, dass die Sonderzeichen meist nicht richtig angezeigt werden, wenn man in UTF-8 exportiert.

Wer das vermeiden will muss einfach den richtigen Unicode-Header mitsenden, dieser lautet:

echo pack("CCC",0xef,0xbb,0xbf);

Dieses Kommando sendet ihr am besten nach den „header“ Kommandos, aber noch vor den Daten, dann zeigt Excel auch die richtigen Daten per Doppelklick an.

P.S. LibreOffice / OpenOffice sind von Haus aus schlau genug und stellen die Daten ohnehin richtig dar, das Problem existiert also wirklich nur für Excel.

Windows Live und Thunderbird

Windows Live und Thunderbird, das hieß lange Zeit „entweder…oder“, aber nie „zusammen“. Bisher zumindest. Microsoft spendiert den Windows Live Mailkonten IMAP, einfach so, ohne „große“ Ankündigung, ohne viel Tamtam … fast hätte ich es überlesen.

Bisher unterstützte Microsoft bei den Windows Live Mailadressen nur EAS (Exchange Active Sync), was – zugegeben – wirklich schneller sein kann (und oft ist) wie das doch recht betagte IMAP. Andererseits ist EAS nicht sehr verbreitet. Zwar beherrscht jedes aktuelle Smartphone EAS mitlerweile (und mein altes Samsung Bada schon länger), schaut man sich allerdings die Desktop-Mail-Clients an sieht es oft Mau aus. Windows Live Mail ist da die erste Wahl, wenn man nicht Outlook (das richtige Outlook, nicht Express) selbst besitzt. Und lange war auch gezwungen, damit zu leben.

Nun funktioniert IMAP bei Windows Live Konten und ich zeige dir nun, wie du Thunderbird einstellt, damit die Mails syncronisiert werden und du auch an deine Termine in Thunderbird (mit Lightning) kommst.

Ich benutzte Thunderbird, du kannst, IMAP sei dank, auch irgendeinen Mailclient benutzen, der dir zusagt.

Windows Live in Thunderbird:

  1. Thunderbird installieren
  2. Lightning installieren (AddOn)
  3. Neues Konto anlegen
  4. Name, E-Mail-Adresse und Passwort solltest du ja kennen
  5. Nun NICHT die POP Variante blind übernehmen, sondern auf „manuell bearbeiten“ klicken (ganz unten als Button)
  6. Posteingang-Server auf IMAP wechseln
  7. Server-Adresse auf „imap-mail.outlook.com“ einstellen, Port 993, Sicherheit „SSL/TLS“, Auth „Passwort, normal“
  8. Postausgang-Server auf „smtp-mail.outlook.com“ einstellen, Port 587 (oder 25, wenn 587 geblockt ist), Sicherheit „STARTTLS“, Auth „Passwort, normal“
  9. Fertig

Für den Kalender machst du folgendes:

  1. In die Onlineversion deines Kalenders gehen
  2. In outlook.com einloggen
  3. oben links auf den Kalender wechseln
  4. Oben den Button „Teilen“ anklicken
  5. gewünschten Kalender wählen
  6. „Link abrufen“
  7. „Erstellen“
  8. Den Link bei „In andere Kalenderanwendungen importieren (ICS)“ kopieren
  9. In Thunderbird „Datei“ -> „Neu“ -> „Kalender“
  10. „Im Netzwerk“
  11. Bei „Adresse“ den Link reinkopieren -> „Weiter“
  12. Fertig

Viel Spaß mit Windows Live, IMAP und einem Mailclienten deiner Wahl.

 

CRUD – Theorie und Praxis

CRUD, dieses Vorgehen sollte eigentlich jeder kennen … falls nicht, CRUD ist die Kurzform für „Create, Read, Update and Delete“ und ist vereinfacht gesagt als Checkliste zu sehen und gilt nicht nur für PHP.

Du hast in deiner Anwendung zum Beispiel eine Liste aller User, die soll editierbar sein. Du kannst nun CRUD als Checkliste benutzen und einzeln abhaken:

  • Create: Kann ich neue User erzeugen? Check!
  • Read: Kann ich eine Liste aller User ausgeben UND kann ich im Editfall einen User darstellen? Check!
  • Update: Kann ich die Daten eines Users ändern? Check!
  • Delete: Kann ich einen User löschen? Check!

Hast du bei allen ein „Check!“, dann bist du technisch auf dem Mindestlevel angelangt. Herzlich Willkommen 😉

Soviel zu Theorie. In der Praxis sehe ich es leider oft, dass CRUD viel zu wörtlich genommen wird. Besonders das C und das U sehe ich oft als zwei Dinge in der Anwendung.

Warum nun ist das schlimm? Nun, ich arbeite mit Legacy-Anwendungen. Diese sind teilweise vor vielen Jahren begonnen und verrichten bis heute ihren Dienst. Innerhalb dieser Anwendungen gibt es immer wieder den Fall, dass eine Datensatzart die CRUD Bedingung erfüllen muss, d.h. ich habe eine Liste von (Beispiel) Usern oder Kunden, die kann man ändern, die kann man neu erzeugen, die kann man löschen usw.

Nun mein Appell an alle: Bitte, fasst C und U zusammen. Bitte!

Es gibt nichts schlimmeres, als dass man ein „create“ Script und ein „update“ Script hat, beide machen im Prinzip das gleiche (Prüfung der Daten, Normalisieren der Daten usw.), aber im Endeffekt hast du 2 Scripte. Du hast also „duplicate code“. Und das ist nicht nur „bad smell„, dies ist einfach nur „bad style“. Eine Änderung an der Logik der User (Stichwort neues Feld) und du musst beide Scripte aktualisieren. Falls deine Anwendung mehrere solcher Listen hat und das neue Feld mehrere betrifft darfst du die „2“ gern entsprechend faktorisieren.

Also, bitte, bau die ein „edit“ Script, prüfe die Variablen, normalisiere diese und mache alles fertig. Dann nur noch die Unterscheidung „neu“ oder „ändern“ und gut ist. Das sind aus meiner Erfahrung nur ein if-else (oder switch) und das entsprechende SQL-Kommando. Die Ausführung des Kommandos ist dann ja wieder das selbe und kann außerhalb der Verzweigung stehen.

Dieses eine Script läßt sich jetzt viel leichter skalieren, verstößt nicht mehr gegen den „copy paste detector“ und läßt dich einfach ruhiger schlafen.

Just my 2 cent ….

No input file specified.

Codeigniter kann einen in den Wahnsinn treiben mit dieser Meldung:

No input file specified.

Sonst nix.

Hier für alle, vor allem für mich, der „fix“ dazu:
In der .htaccess hinter dem „index.php“ aber noch vor dem „/“ ein „?“:

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f 
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?/$1 [L]

Zumindest bei meinen Projekten funktioniert dann wieder alles wie es soll.

Hat YAGNI ausgedient?

Ich las eben einen interessanten Artikel im phpMagain online. In „Abwärtskompatibilität vs. langfristiges Planen“ geht es über einen Blogbeitrag von Anthony Ferrara, in der dieser u.a. darüber schreibt, dass er die Optionen seiner Funktionen als array anlegt, obwohl das ja teilweise gar nicht sein müsse. In die Zukunft gesehen macht es aber Sinn, da ja bald neue Optionen hinzukommen werden, da sich jede Software weiterentwickelt und seine Funktion somit flexibel ist und ihre Signatur sich nicht weiter ändern muss.

Allerdings, und das steht ja auch im Artikel des phpMagazins, wiederspricht dies dem YAGNI Prinzip, das – vereinfacht – besagt, dass du alles, was du aktuell nicht brauchst, auch nicht entwickeln sollst.

Ich finde, dass passt dann nur auf Software, die du einmal entwickelst und die dann einfach vor sich hin altert. Software, die du vorher im Detail planst und dann nie wieder ansiehst. Kurz, Software, die hoffentlich heute in der Form nicht mehr gebaut wird.

Heute verändert sich Software stetig und ständig, „und das ist auch gut so“, denn sonst würden wir alle niemals Updates installieren müssen. Aber im Gegenteil müssen wir heutzutage so viele Updates installieren, dass manchen Hersteller gar nicht mehr nervt fragt, sondern uns ganz bequem mit „Silent updates“ auf dem neuesten Stand hält.

IMHO werden Anwendungen und Webseiten heute um ein vielfaches schneller und öfter aktualisiert wie noch vor wenigen Jahren. Und Software, die aktualisiert wird, wird oft auch erweitert. Es werden ja nicht nur Sicherheitslücken geschlossen oder Bugs gefixed, es kommen oft auch neue Features und Funktionen hinzu, altbekanntes fällt manchmal weg, kurz: Die Software verändert sich und damit auch ihr Code, ihre Funktionen und dessen Signaturen.

Was hat das nun mit YAGNI zu tun? Nun, YAGNI würde besagen, dass man eine Funktion minimalst aufbauen soll, ein Beispiel, eine Funktion liefert uns Benutzerdaten aus einer Datenbank:

public function getUser() {
//...
}

Diese Funktion würde alle User zurückliefern. Im Laufe des Lebens der Anwendung merken wir, dass ein Filter auf „getUser()“ wohl sinnvoll wäre, also ändern wir die Signatur:

public function getUser($id)

liefert nun genau einen User mit einer speziellen Id.

public function getUser($id = -1, $name)

kann nun auch einen User nach Namen liefern, wenn wir id auf -1 setzen.

public function getUser($id = -1, $name, $nameAsLike)

kann nun auch – bei $nameAsLike=true und id=-1 – einen Namen „teilweise“ liefern.

Diese Liste ließe sich nun bestimmt weiter fortsetzen, ihr kennt das sicher alle. Sicher entspricht dies dem YAGNI Prinzip, denn im Laufe der Versionen der Software kam immer nur genau so viel dazu, wie unbedingt erforderlich war. Aber war das gut so?

Vorausschauender wäre es gewesen, sich kurz Gedanken zu machen und dann zu entscheiden

public function getUser(array $options=array())

Nun kann dort auch jeder der obigen Evolutionsschritte der Software eingebracht werden, die Signatur der Funktion braucht allerdings dazu nicht geändert zu werden und damit gibt es auch weniger potentielle Fehlerquellen im Rest des Codes.

Vielleicht müssen wir vom starren YAGNI weg, hin zu einem YDNNI, einem „You Defenitly Not Need It“, einem Paradigma, dass es erlaubt, vorausschauend zu Entwicklen, dass einem aber trotzdem untersagt, völlig Sinnfreie oder sogar Kontraproduktive Dinge zu entwickeln.

Die Sache mit dem array scheint sich langsam aber sicher dank oder trotz YAGNI zur „Best Practice“ durchzusetzen. Setzt ihr Optionen auch als array um oder benutzt ihr da völlig andere Wege?

 

PHP – foreach „greift“ nicht, keine Iteration

Kleiner Hinweis: Wenn bei euch eine „foreach“ Schleife nicht greift, obwohl alles richtig zu sein scheint – das array ist da, Werte sind drin, sogar die richtigen 😉 – und trotzdem keine Iteration über das array stattfindet, dann sucht mal vor Ausführung des foreachs nach array-Iterations Funktionen, die das komplette Array durchlaufen, z.B.: array_map, array_walk, usw.

Die Ursache ist: Durch den kompletten Durchlauf des Arrays steht der interne Pointer (wir erinnern uns dunkel, PHP ist in C/C++ geschrieben) immer noch auf dem letzten Element, die foreach-Schleife kann also nicht loslaufen, weil Sie – rein technisch – schon am Ende ist und „überspringt“ das foreach.

Die Lösung ist trivial: Nach der Iterationsfunktion oder direkt vor dem foreach setzt ihr

reset($myArray);

Das reset setzt euer Array intern wieder auf das erste Element und schon funktioniert eure foreach-Schleife wieder – die C/C++ und Java-Entwickler kennen das Problem 😉