<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Lieber Linux &#187; SQL</title>
	<atom:link href="http://www.lieber-linux.de/tag/sql/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.lieber-linux.de</link>
	<description>Linux und Open Source Software im Blog</description>
	<lastBuildDate>Thu, 26 Jan 2012 17:58:46 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2</generator>
		<item>
		<title>Memcache &#8211; gib mir Speed!</title>
		<link>http://www.lieber-linux.de/2009/10/memcache-gib-mir-speed/</link>
		<comments>http://www.lieber-linux.de/2009/10/memcache-gib-mir-speed/#comments</comments>
		<pubDate>Sat, 17 Oct 2009 11:28:22 +0000</pubDate>
		<dc:creator>Nudge</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Tipp]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[Cache]]></category>
		<category><![CDATA[memcache]]></category>
		<category><![CDATA[memcached]]></category>
		<category><![CDATA[Server]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://www.lieber-linux.de/?p=625</guid>
		<description><![CDATA[Ich habe diese Woche den memcache-daemon memcached in Version 1.4.2 mit der PHP-extension memcache ausprobiert und bin einfach nur begeistert. Was ist denn Memcache? Memcache ist ein Dienst, der es erlaubt, Daten im Arbeitsspeicher vorzuhalten. Daneben erlaubt er es auch noch, dies über mehrere Server zu verteilen, also ein richtiges Speicher-Netzwerk aufzubauen. Und Arbeitsspeicher ist [...]]]></description>
			<content:encoded><![CDATA[<p>Ich habe diese Woche den memcache-daemon memcached in Version 1.4.2 mit der PHP-extension memcache ausprobiert und bin einfach nur begeistert.</p>
<h3>Was ist denn Memcache?</h3>
<p>Memcache ist ein Dienst, der es erlaubt, <strong>Daten im Arbeitsspeicher</strong> vorzuhalten. Daneben erlaubt er es auch noch, dies über mehrere <strong>Server</strong> zu verteilen, also ein richtiges Speicher-Netzwerk aufzubauen. Und Arbeitsspeicher ist eine der schnellsten Zugriffsformen auf Daten, die wir zur Zeit haben. Memcache kann durch das <strong>Zwischenspeichern</strong> von Daten, die sonst mühsam aus anderer Stelle geholt werden müssen, das Leben leichter und angenehm schneller gestalten.</p>
<p><span id="more-625"></span>Dazu muss man sagen, dass ja Webanwendungen von Seitenaufruf zu Seitenaufruf jeweils neu initialisiert werden müssen. Als Benutzer in einer Sitzung (<strong>Session</strong>) ist einem das oft nicht bewusst, aber es kostet den Server bei jedem Klick eine entsprechende Zeit, die Session zu restaurieren und die Daten wieder so herzustellen, damit die nächste Aktion ausgeführt werden kann. Die Sessions werden in einer Datei auf dem Server abgelegt. Das heißt also auch Festplattenaktivität pro Klick. Das ist doof. Noch dümmer, dass man nicht wirklich viel in solch eine Session legen kann und sollte. Je größer das Session-File, desto langsamer wird jeder einzelne Aufruf. Dinge also, die nicht wirklich essentiell sind, holt man also immer wieder neu aus einer <strong>Datenbank</strong> oder anderen Quellen.</p>
<p>Daneben gibt es noch <strong>Session-unabhängige Daten</strong>. Bei einem News-Portal also die aktuellen Beiträge zum Beispiel. Doch die sollte man nicht jedem der Millionen von Nutzern in die Session legen. Dabei sind diese ständig gefragt, was macht man also damit? Memcache ist hier die richtige Lösung. Mit Memcache lassen sich diese nutzerunabhängigen Daten genau einmal speichern, aber für jeden Nutzer in hoher <strong>Geschwindigkeit</strong> bereitstellen. Das macht richtig Spaß.</p>
<h3>Was geht in Memcache rein?</h3>
<p>Das Beste ist: Memcache bildet nur eine simple Zuweisung von <strong>Key-Value-Paaren</strong> ab. Unter einer Zeichenkette als Schlüssel, der maximal 250 Zeichen Länge betragen darf, werden einfache Zeichenketten als Werte hinterlegt. Die Werte dürfen maximal 1 MB Größe haben. Was man darin speichert, ist tatsächlich vollkommen egal. Man kann also gezielt eine Datenbank beschleunigen oder aber auch Template-Engines entlasten, also ganze HTML-Vorlagen ablegen, vielleicht auch schon komplett mit allen Inhalten gerendert. Ebenso lassen sich die Einträge unabhängig von deren Nutzung befüllen, zum Beispiel nachts, wenn die Last der Server geringer ist. Tagsüber stehen dann z.B. aggregierte Daten zum schnellen Abruf bereit.</p>
<p>Die <strong>PHP</strong>-Schnittstelle ist dazu mit einer <strong>automatischen Serialisierung</strong> implementiert. Man kann also einfach komplexere Objekte und Arrays einfach hineinwerfen &#8211; und so kommen sie auch heraus. Einzig und allein Pointer wie Dateizeiger oder auch (Datenbank-)Verbindungen sollte man nicht hineinwerfen, denn Ressourcen können im Allgemeinen nicht richtig wiederhergestellt werden. Jeder Eintrag kann dabei on-the-fly mit zlib komprimiert werden, sollte es sich um größere Datenmengen handeln, um im 1-MB-Bereich zu bleiben oder einfach aus Speichergründen. Der Dienst <strong>memcached</strong> wird außerdem mit einer Option -m für die Gesamtspeichergröße</p>
<pre>/usr/local/bin/memcached -d -m &lt;Anzahl der MB&gt; -p 11211 -l 127.0.0.1 -u nobody</pre>
<p>gestartet, sodass bei -m 2048 maximal 2 GB des Arbeitsspeichers belegt werden. Nicht zuletzt wird beim Zwischenspeichern ein Zeitlimit gesetzt, wie lange der Cache-Eintrag gültig sein soll.</p>
<h3>Anwendung am Beispiel www.ebrosia.de</h3>
<p>Zunächst habe ich ein Profiling unserer Startseite gemacht. Die sollte wohl sehr häufig aufgerufen werden. Insgesamt bietet allein diese Seite Anlass für über 100 Datenbank-Abfragen, wenn man alles streng nimmt. Also ist das mein erstes Optimierungsgebiet gewesen. Es gibt natürlich Abfragen, die man besser nicht zwischenspeichert, wie zum Beispiel den Warenkorb des Benutzers &#8211; der sollte immer auf die Sekunde aktuell sein. Die Zusammenfassung des Warenkorbs (x Artikel mit y Gesamtpreis) wandert also am besten in die Session: Verbraucht nicht viel Platz, ist nutzerabhängig und wird bei einer Änderung am Warenkorb neu errechnet, also eher selten.</p>
<p>Bei der Entscheidung, ob ganze <strong>Templates</strong> optimiert werden sollen, habe ich mich dagegen entschieden: Die Mehrzahl der Seiten bietet für eingeloggte Nutzer individualisierte Inhalte, dazu sind die Templates nicht wirklich die Zeitfresser, da reines HTML und PHP zum Einsatz kam, also keine Layout-Engine verwendet wird. Die Seiten leben eher von den kleinen Abfragen an die Datenbank. Hier und da geht es um Links zu einem Artikel, um einen Preis, einen Artikelnamen. Speziell zu Wein kamen noch das Land, ein Gebiet oder eine Rebsorte hinzu.</p>
<p>Wenn man einen <strong>Shop</strong> betreibt, dann sind die Produktdaten das A und O, gerade bei etwa 1000 Artikeln. In fast jeder Shop-Seite, besonders auf der Startseite, kommen mehrere, auch wechselnde Artikel vor. Jeder Artikel hat einen Namen, einen Preis, einen Rabatt und eine Lieferbarkeit. Diese Daten werden eventuell mehrfach pro Sekunde abgerufen, aber vielleicht nur einmal im Monat geändert, zum Beispiel bei einer Rabatt-Aktion. Setzt man hier ein <strong>Zeitlimit</strong> von 10-20 Minuten an, sollten also geschätzte 90% der Aufrufe mit Memcache abgefangen werden, ohne dass die Aktualität leidet. Ich habe mich für ein kurzes Zeitfenster von 10 Minuten entschieden, um im Fehlerfall flexibler zu bleiben.</p>
<p>Also habe ich dort angesetzt. Memcache bildete eine Art <strong>Zwischenschicht</strong> zwischen dem <strong>Shop</strong> als Gestaltung und dem <strong>Datenbank-Backend</strong>. Letztlich konnte ich so mit nur einer kleinen Memcache-Implementierung im Backend gleich sehr viele Shop-Seiten verbessern, die auf die optimierten Funktionen mit den <strong>SQL-Abfragen</strong> zugreifen. Mit der Zwischenspeicherung von Preisen, Rabatten, Namen von Artikeln und Kategorien habe ich die Startseite auf ein durchschnittliches Volumen von etwa 5 SQL-Anfragen gedrückt. Diese Anfragen gehen auf die stetige Erneuerung von Cache-Einträgen wie auch das Rotieren von Produkten in Teasern zurück. Letztlich betrug die Zeit der Auslieferung der Startseite nur noch 35-50 Millisekunden (PHP-Start bis PHP-Ende). Seiten ohne SQL-Inhalte bewegten sich gleichen Zeitrahmen. Man konnte demnach davon ausgehen, dass das <strong>Caching</strong> die Belastung des MySQL-Servers auf ein Minimum reduziert hatte.</p>
<p>Im zweiten Schritt ging es dann an Artikel- und Kategorie-Seiten. Diese waren schon weitgehend durch den vorigen Schritt entlastet. Es waren nur noch wenige Handgriffe zu tun, um auch hier an die gleichen Rendering-Zeiten zu gelangen. In Frieden ließ ich den individuellen Konto-Bereich der Kunden. Hier wäre auch das Optimierungspotenzial geringer. Mit dem investierten Aufwand bin ich bereits weit genug gekommen für eine erste Runde.</p>
<h3>Rollout auf dem Webserver</h3>
<p>Libevent installiert und memcache kurz kompiliert, schon konnte es losgehen. Der Dienst startete angenehm einfach. Das PHP-Modul ist mit einem einfach <strong>phpize</strong>, <strong>configure</strong> und <strong>make</strong> ebenso leicht aufgesetzt. Jetzt nur noch das <strong>Modul</strong> in der <strong>php.ini</strong> fest eingetragen und nach einem kurzen Neustart des Apache sagte mir ein Testskript &#8220;Ja, es ist angerichtet.&#8221; <img src='http://www.lieber-linux.de/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>Der Shop wurde synchronisiert, und schwupps, kamen erste Ergebnisse im Cache an. Das Gefühl eines schnelleren Arbeitens war wirklich omnipräsent, das fühlte sich gleich gut an. Nach einigen Stunden Laufzeit hatte Memcache eine <strong>Trefferquote</strong> von etwa 87% zu verzeichnen, und die Last auf dem DB-Server war damit drastisch gefallen. An die Optimierung weiterer Bereiche kann nun Schritt für Schritt herangegangen werden. <strong>Nagios </strong>zeichnet flachere Kurven, und der Admin ist zufrieden. Jetzt kann Weihnachten kommen. <img src='http://www.lieber-linux.de/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.lieber-linux.de/2009/10/memcache-gib-mir-speed/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>MySQL vs Postgres mal ganz ohne Technik</title>
		<link>http://www.lieber-linux.de/2008/09/mysql-postgres-ohne-technik/</link>
		<comments>http://www.lieber-linux.de/2008/09/mysql-postgres-ohne-technik/#comments</comments>
		<pubDate>Tue, 23 Sep 2008 20:09:15 +0000</pubDate>
		<dc:creator>Nudge</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Benutzer]]></category>
		<category><![CDATA[Navigation]]></category>
		<category><![CDATA[Postgresql]]></category>
		<category><![CDATA[Rechte]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Vergleich]]></category>

		<guid isPermaLink="false">http://www.lieber-linux.de/?p=139</guid>
		<description><![CDATA[Wenn man den ganzen Kladderadatsch von Performance und Features weglässt, so gibt es immer noch einen ganz gewaltigen Punkt für die Beurteilung einer Datenbank: Wie sie sich dem Benutzer gegenüber präsentiert. Und dies möchte ich heute ganz ohne Ausschweifungen zusammenfassen. Die Installation Fangen wir mal mit der Installation an. Unter Linux gibt es in jeder [...]]]></description>
			<content:encoded><![CDATA[<p>Wenn man den ganzen Kladderadatsch von Performance und Features weglässt, so gibt es immer noch einen ganz gewaltigen Punkt für die Beurteilung einer Datenbank: Wie sie sich dem Benutzer gegenüber präsentiert. Und dies möchte ich heute ganz ohne Ausschweifungen zusammenfassen.</p>
<h3><span id="more-139"></span></h3>
<h3>Die Installation</h3>
<p>Fangen wir mal mit der Installation an. Unter Linux gibt es in jeder Distribution die bequeme Art des Paketmanagers. Unter Windows gibts Install-Programme (bei Postgresql ab Version 8). Wer Binaries vertraut, hat so oder so ziemlich schnell die Datenbank-Umgebung installiert. Insofern gibts hier nix zu beanstanden, alles sehr einfach.</p>
<p>Wer selbst kompilieren will, um auf dem neuesten Stand zu sein, sollte natürlich die üblichen Verdächtigen configure und make benutzen können. Aber wer will das schon? Das lassen wir der Einfachheit halber ganz schnelle beiseite. <img src='http://www.lieber-linux.de/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<h3>Aller Anfang ist schwer</h3>
<p>Ist die Datenbank installiert, so will man diese natürlich gleich ausprobieren. Wie macht man denn das überhaupt? Am schnellsten geht das über stets mitgelieferte Kommandozeilen-Programm. Bei Postgres heißt das <strong>psql</strong>, bei MySQL einfach <strong>mysql</strong>.</p>
<pre>postgres@lx:/$ psql
Dies ist psql 8.3.3, das interaktive PostgreSQL-Terminal.

Geben Sie ein:  \copyright für Urheberrechtsinformationen
                \h für Hilfe über SQL-Anweisungen
                \? für Hilfe über interne Anweisungen
                \g oder Semikolon, um eine Anfrage auszuführen
                \q um zu beenden

postgres=#</pre>
<p>oder auch</p>
<pre>lx:/home/nudge# mysql -u root -p
Enter password:
Welcome to the MySQL monitor.Â  Commands end with ; or \g.
Your MySQL connection id is 41
Server version: 5.0.51a-12 (Debian)

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql&gt;</pre>
<h3>Der Benutzer</h3>
<p>Um sich erfolgreich anzumelden, braucht man einen Nutzernamen, einen Host und eventuell ein Passwort. Dies alles muss vorher in der Datenbank über die Rechtevergabe konfiguriert sein. Postgresql setzt hier ganz stark auf System-Benutzer, MySQL pflegt Nutzer über Tabellen in MySQL selbst. Beides hat Vor- und Nachteile.</p>
<p>Postgresql zum Beispiel ist dadurch recht robust: Man braucht kein zusätzliches Datenbank-Passwort. Und ordentliche Nutzerpflege vorausgesetzt, ist das auch das sicherste. Allerdings sind Datenbanken meist dort installiert, wo Server rauschen und viele Homepage-Hobby-Admins auf einer Maschine arbeiten. Nicht jeder braucht dabei einen System-Account. Da ist MySQL besser aufgestellt: Nutzer und Rechte können im System ganz einfach gepflegt werden. Postgresql muss neu konfiguriert werden, wenn ein Nutzer hinzukommt.</p>
<h3>Navigation in der Datenbank</h3>
<p>Ist man erst einmal in der Kommandozeile, gibts gleich tausend weitere Fragen: Wo bin ich? Was ist um mich herum? Wie bewege ich mich? Wie komme ich hier heil wieder raus? Wer hilft mir?</p>
<p>Beide Kommandozeilen bieten ihre Hilfe über die Tastenkombination <span style="color: #ff0000;">\h</span> an. Sehr praktisch &#8211; kein Umdenken. <img src='http://www.lieber-linux.de/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  Die Ergebnisse unterscheiden sich jedoch gewaltig: Während MySQL eine kurze Übersicht über die Basic-Befehle ausgibt, öffnet Postgresql eine Hilfe-Shell mit vim-ähnlicher Syntax nur für SQL-Befehle. Mit einer solchen Shell kann kein Anfänger zurechtkommen! Hier macht Postgresql ganz schnell klar, für welchen Benutzerkreis es gedacht ist. Nix für NAU&#8217;s (Normalster anzunehmender User). Also muss man bei Postgresql externe Dokumentation bemühen. Wobei sich das auch bei MySQL empfiehlt. So fährt man bequemer.</p>
<p>Eine Auflistung aller Datenbanken gibts unter MySQL nach einem beherzten <span style="color: #ff0000;">SHOW DATABASES;</span> Postgresql schafft dies mit einem kurzen <span style="color: #ff0000;">\l</span>. MySQL kann man mit <span style="color: #ff0000;">USE DATABASE;</span> die Datenbank wechseln, bei Postgresql per <span style="color: #ff0000;">\c</span> (CONNECT). Die Tabellen einer Datenbank sieht man unter MySQL mit <span style="color: #ff0000;">SHOW TABLES;</span> unter Postgresql per <span style="color: #ff0000;">\d</span>. Was L mit Datenbanken zu tun hat, ist mir unklar, \d steht für DESCRIBE und erklärt auch einzelne Tabellen mit <span style="color: #ff0000;">\d [TABELLENNAME]</span>. Die Kürze der psql-Befehle ist natürlich bei der täglichen Benutzung von Vorteil. Hier wird wieder mal klar: Postgresql richtet sich an fortgeschrittene Nutzer, MySQL ist sehr einfach ausgelegt. Beide Datenbanken können per <span style="color: #ff0000;">\q</span> verlassen werden, MySQL zusätzlich über den Alias <span style="color: #ff0000;">QUIT</span>.</p>
<h3>Tabellen und Datenbanken</h3>
<p>Datenbanken werden von beiden DBMS per <span style="color: #ff0000;">CREATE DATABASE [DATENBANKNAME]</span> angelegt, per <span style="color: #ff0000;">DROP DATABASE [DATENBANKNAME]</span> gelöscht. Postgresql kennt dazu die externen Tools createdb und dropdb. Tabellen legt man analog dazu per <span style="color: #ff0000;">CREATE TABLE [TABELLENNAME]</span> an und löscht sie per <span style="color: #ff0000;">DROP TABLE [TABELLENNAME]</span>. Erklären kann man sich den Aufbau einer MySQL-Tabelle mit <span style="color: #ff0000;">SHOW CREATE TABLE [TABELLENNAME]</span>, Postgresql kann dies wie bereits gezeigt per <span style="color: #ff0000;">\d [TABELLENNAME]</span>.</p>
<p>Achtung: Sehr bekannt ist die Tatsache, dass sich Postgresql mehr an den SQL-Standard hält als MySQL. Doch was bedeutet das jenseits verschachtelter Abfragen und unverständlichem Spaghetti-Code? Zum Beispiel dies: Datenbank und Tabellennamen sind bei Postgresql grundsätzlich in Kleinbuchstaben gehalten. Namen mit Großbuchstaben sind durch Apostrophe einzuschließen. Wer also auf Namen wie <span style="color: #ff0000;">ArtikelVarianten</span> oder <span style="color: #ff0000;">KalenderOptionen</span> steht, sollte stets <span style="color: #ff0000;">&#8216;ArtikelVarianten&#8217;</span> bzw. <span style="color: #ff0000;">&#8216;KalenderOptionen&#8217;</span> schreiben oder auf eine andere Worttrennung umsteigen, wie den beliebten Unterstrich: <span style="color: #ff0000;">kalender_optionen</span>. Davon bin ich leider kein großer Fan, das sieht immer so oll aus&#8230; <img src='http://www.lieber-linux.de/wp-includes/images/smilies/icon_neutral.gif' alt=':-|' class='wp-smiley' /> </p>
<p>Was ganz nett ist: Wenn man im MySQL-Client ein Query absetzt, so erhält man neben den Ergebnissen auch eine Anzeige, wie lange diese Anfrage gedauert hat. Hat man bei seiner Datenbank-Konzeption alles richtig gemacht, so sollte nur in wenigen Fällen etwas anderes als &#8220;(0,00 sec)&#8221; stehen. Der Postgres-Client psql schweigt an dieser Stelle per default. Mit dem Befehl <strong>\timing</strong> kann man die Zeitmessung aktivieren, erhält dann allerdings nur das Timing, nicht das Ergebnisset, allerdings auf die Mikrosekunde genau.</p>
<h3>Das erste Fazit</h3>
<p>Insgesamt macht MySQL einen sehr einfachen und leicht erlernbaren Eindruck, während Postgresl mit seinen Kurzbefehlen, seiner ungewohnten Syntax und oft komplizierten Administration Einsteiger eher abschreckt. Für den Power-User hält Postgres jedoch mehr Optionen bereit. Auf einem Level von Hobby-DB-Admins gesehen, sind beide Datenbanken natürlich voll funktionstüchtig und die Qual der Wahl zunächst wohl eher reine Geschmackssache. Wer Postgres mit PHP benutzen möchte, der sollte sich den Performance-Schlucker pg_connect() genauer ansehen &#8211; hier geht oft mehr Zeit verloren als beim Query selbst.</p>
<p>Und damit kommen wir auch schon zum Ende. In der nächsten Folge wird es um Datentypen und auch um ganz echte Daten gehen &#8211; denn dafür sind die Programme ja schließlich gemacht. Es lohnt sich also auf jeden Fall dranzubleiben!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lieber-linux.de/2008/09/mysql-postgres-ohne-technik/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>SQL im Webshop: Suche nach Modified</title>
		<link>http://www.lieber-linux.de/2008/07/sql-im-webshop-suche-nach-modified/</link>
		<comments>http://www.lieber-linux.de/2008/07/sql-im-webshop-suche-nach-modified/#comments</comments>
		<pubDate>Thu, 31 Jul 2008 14:22:57 +0000</pubDate>
		<dc:creator>Nudge</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Cache]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[Query]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Webshop]]></category>

		<guid isPermaLink="false">http://www.lieber-linux.de/?p=24</guid>
		<description><![CDATA[Größere Netzwerke, Suchmaschinen oder auch mal eben der kleine Statusbalken arbeiten viel besser, wenn man einen Zeitstempel zur Verfügung stellen kann à la &#8220;Dieser Artikel oder dieses Produkt wurde zuletzt geändert am &#8230;&#8221;. Das ist allerdings nicht ganz so easy, wenn sich die Daten des Satzes in verschiedenen Tabellen befinden. Also muss man die sich [...]]]></description>
			<content:encoded><![CDATA[<p>Größere Netzwerke, Suchmaschinen oder auch mal eben der kleine Statusbalken arbeiten viel besser, wenn man einen Zeitstempel zur Verfügung stellen kann à la &#8220;Dieser Artikel oder dieses Produkt wurde zuletzt geändert am &#8230;&#8221;.</p>
<p>Das ist allerdings nicht ganz so easy, wenn sich die Daten des Satzes in verschiedenen Tabellen befinden. Also muss man die sich mühevoll zusammenklauben. Bei uns im Shop sind es eigentlich nur eine Handvoll Tabellen: Der Artikeleintrag in der Warenwirtschaft, die Varianten, die Preise, Rabatte, Shop-Eintrag, Shop-Texte und Shop-Fotos.</p>
<p><span id="more-24"></span>Die Einträge wurden aus eben diese Tabellen zusammengesucht. Aus Performance-Gründen bieten sich hier Stored Procedures an:<br />
<span style="color: #ff0000;">DELIMITER &#8216;$&#8217;;<br />
CREATE FUNCTION f_getModified(&#8230;xyz&#8230;) RETURNS Datetime READS SQL DATA<br />
BEGIN<br />
DECLARE last DATETIME;<br />
DECLARE cur DATETIME;<br />
SELECT Timestamp INTO last FROM Tbl_XYZ INTO last WHERE xyz;<br />
SELECT Timestamp INTO cur FROM Tbl_XYZ cur WHERE xyz;<br />
SET last = IF(cur &gt; last, cur, last);<br />
&#8230;<br />
RETURN last;<br />
END$<br />
DELIMITER &#8216;;&#8217;$</span></p>
<p>Natürlich schrumpft die Performance bei zunehmender Fragmentierung der Produktdaten erheblich, da die Berechnungskosten linear steigen. Aus diesem Grund habe ich überlegt, die Tabellen über INNER JOINS zu verknüpfen, und die Zeitstempel zunächst in einem Ritt zu holen:<br />
<span style="color: #ff0000;">DELIMITER &#8216;$&#8217;;<br />
CREATE FUNCTION f_getModified(&#8230;xyz&#8230;) RETURNS Datetime READS SQL DATA<br />
BEGIN<br />
DECLARE last DATETIME;<br />
DECLARE cur DATETIME;<br />
SELECT a.Timestamp, b.Timestamp INTO last,cur FROM Tbl_XYZ a INNER JOIN TblXYZ b ON a.x=b.x AND a.y=b.y WHERE xyz;<br />
SET last = IF(cur &gt; last, cur, last);<br />
RETURN last;<br />
END$<br />
DELIMITER &#8216;;&#8217;$</span></p>
<p>Auf meine 7 Tabellen angewendet, gibt das immerhin einen 10%-igen Performance-Schub. Nicht unerheblich, aber trotzdem nicht der Bringer. Anfangs waren es über 50% Geschwindigkeitsvorteil, als ich mit einfachen INNER JOINS über die ersten Tabellen arbeitete. Doch da es nicht immer entsprechende Einträge geben muss, ist man hier und da gezwungen, ein paar LEFT JOIN einzusetzen, welche als OUTER JOIN natürlich langsamer sind.</p>
<p>Ein weiteres Problem ist, dass nicht alle Tabellen einen Eintrag pro Produkt bieten, d.h. an dieser Stelle sind Sub-SELECTS vonnötigen, die den Zeitstempel über MAX(Timestamp) zunächst in der Ziel-Tabelle aggregieren, bevor der INNER JOIN einsetzt.</p>
<p>Letztendlich hatte ich bei einer entsprechend aufbereiteten Seite doch eher dazu tendiert, die bereits mit dem PHP-Script ausgelesenen Timestamps und die fehlenden Stempel per Hash-Scan zu ergänzen. An dieser Stelle konnte ich die Kosten für die Zeitstempel auf 20% der Procedure-Kosten drücken &#8211; allerdings ist diese Vorgehensweise nicht an allen Stellen die beste.</p>
<p>Doch bietet eine Seite nicht auch noch mehr? FAQs? Bewertungen? Mitkaufartikel? Hat sich die Seite nicht auch deswegen geändert, weil hier und da ein Eintrag dazugekommen ist? Was passiert, wenn sich eine Seite geändert hat, weil ein Eintrag <strong>wegfiel</strong>? Gar nicht so einfach, und ich möchte gern wissen, wie das &#8220;große&#8221; Shops so machen&#8230;Wer Ideen hat, ist zum Posten gerne eingeladen!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lieber-linux.de/2008/07/sql-im-webshop-suche-nach-modified/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

