<?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>treibsand.com &#187; PostgreSQL</title>
	<atom:link href="http://www.treibsand.com/tag/postgresql/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.treibsand.com</link>
	<description></description>
	<lastBuildDate>Tue, 27 Dec 2011 12:46:03 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>Backup einer großen PostgreSQL Datenbank</title>
		<link>http://www.treibsand.com/2009/06/19/backup-einer-grosen-postgresql-datenbank/</link>
		<comments>http://www.treibsand.com/2009/06/19/backup-einer-grosen-postgresql-datenbank/#comments</comments>
		<pubDate>Fri, 19 Jun 2009 10:10:45 +0000</pubDate>
		<dc:creator>Toast</dc:creator>
				<category><![CDATA[Unix]]></category>
		<category><![CDATA[Backup]]></category>
		<category><![CDATA[Datenbank]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Write-Ahead-Log]]></category>

		<guid isPermaLink="false">http://www.treibsand.com/?p=326</guid>
		<description><![CDATA[Um eine Datenbank zu sichern, wird üblicherweise ein SQL Dump erzeugt, welcher dann bei einem Ausfall wieder eingespielt werden kann. Bei kleineren Datenbank ist das auch durchaus ein guter Weg. Wenn allerdings eine Datenbank z.B. größer als 20GB wird, dann dauert der Dump extrem lange und belastet das System. PostgreSQL bietet aber auch die Möglichkeit [...]]]></description>
			<content:encoded><![CDATA[<p>Um eine Datenbank zu sichern, wird üblicherweise ein SQL Dump erzeugt, welcher dann bei einem Ausfall wieder eingespielt werden kann. Bei kleineren Datenbank ist das auch durchaus ein guter Weg. Wenn allerdings eine Datenbank z.B. größer als 20GB wird, dann dauert der Dump extrem lange und belastet das System.<br />
<span id="more-326"></span></p>
<p>PostgreSQL bietet aber auch die Möglichkeit im Betrieb ein sogenanntes Write-Ahead-Log (WAL), neben den eigentlichen Datenbestand, auf die Festplatte zu schreiben. Es enthält alle Aufzeichnungen sämtlicher im Datenbanksystem vorgenommenen Schreiboperationen. Falls das System ausfällt, können diese Aufzeichnungen verwendet werden, um die Datenbank wieder herzustellen. Es handelt sich hierbei um das gleiche Prinzip wie ein &#8220;Journal&#8221; von Linux Dateisystemen. </p>
<p>Eigentlich wird das Write-Ahead-Log in regelmäßigen Abständen mit dem Datenbestand abgeglichen und wieder gelöscht, da es nicht mehr benötigt wird. Es kann aber auch für eine Datensicherung verwendet werden. Die Aufzeichnungen bestehen aus Segmenten,  je 16MB groß und im Verzeichnis <b>pg_xlog</b> zu finden. </p>
<p>Um eine Datensicherung mit WAL zu betreiben, braucht man als erstes eine Basissicherung. Hierfür kann ein einfaches Shellscript verwendet werden:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/bin/sh</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">set</span> <span style="color: #660033;">-e</span>
<span style="color: #007800;">filename</span>=<span style="color: #000000; font-weight: bold;">/</span>data<span style="color: #000000; font-weight: bold;">/</span>wal_archive<span style="color: #000000; font-weight: bold;">/</span>basebackup_<span style="color: #000000; font-weight: bold;">`</span><span style="color: #c20cb9; font-weight: bold;">hostname</span><span style="color: #000000; font-weight: bold;">`</span>_$<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">date</span> +<span style="color: #ff0000;">'%Y-%m-%dT%H%M%S.%N%z'</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>.tar.gz
psql <span style="color: #660033;">-U</span> postgres <span style="color: #660033;">-c</span> <span style="color: #ff0000;">&quot;SELECT pg_start_backup('<span style="color: #007800;">$filename</span>');&quot;</span> <span style="color: #000000; font-weight: bold;">&gt;</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null
<span style="color: #c20cb9; font-weight: bold;">tar</span> <span style="color: #660033;">--force-local</span> <span style="color: #660033;">-C</span> <span style="color: #000000; font-weight: bold;">/</span>data <span style="color: #660033;">-c</span> <span style="color: #660033;">-z</span> <span style="color: #660033;">-f</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$filename</span>&quot;</span> <span style="color: #660033;">--anchored</span> <span style="color: #660033;">--exclude</span>=pg_xlog pgsql <span style="color: #000000; font-weight: bold;">||</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #007800;">$?</span> <span style="color: #660033;">-eq</span> <span style="color: #000000;">2</span><span style="color: #7a0874; font-weight: bold;">&#93;</span>
psql <span style="color: #660033;">-U</span> postgres <span style="color: #660033;">-c</span> <span style="color: #ff0000;">&quot;SELECT pg_stop_backup();&quot;</span> <span style="color: #000000; font-weight: bold;">&gt;</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null</pre></div></div>

<p>Mit den PostgreSQL Befehlen <b>pg\_start\_backup()</b> und <b>pg\_stop\_backup()</b> kann das komplette Datenbanksystem gesichert werden. Das erzeugte Tarball wird unter <b>/data/wal_archive</b> gespeichert. Die PostgreSQL Installation wird unter <b>/data/pgsql</b> erwartet.</p>
<p>Nachdem die Basissicherung erstellt wurde, kann PostgreSQL für WAL konfiguriert werden. PostgreSQL selber macht hier keine Vorschriften, wie die WAL Segmente archiviert werden sollen, es können beliebige Shell Befehle aufgerufen werden. Man hat z.B. die Möglichkeit die Segmente einfach mit <b>cp</b> zu kopieren, könnte sie aber auch mit <b>rsync</b> auf einen anderen Rechner schieben. Die Konfiguration wird in der Datei <b>postgresql.conf</b> vorgenommen:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">archive_mode = on
archive_command = <span style="color: #ff0000;">'test ! -f /data/wal_archive/%f &amp;&amp; cp %p /data/wal_archive/%f'</span></pre></div></div>

<p>Es ist hier wichtig, dass keine vorhandenen Dateien überschrieben werden, deshalb wird vor dem kopieren getestet, ob die entsprechende Datei schon vorhanden ist. Der Platzhalter <b>%f</b> ist der Dateiname für die Zieldatei, <b>%p</b> ist die zu kopierende Datei mit vollständigem Pfad. </p>
<p>Nachdem PostgreSQL neu gestartet wurde, werden die WAL Dateien, sofern 16MB Daten geschrieben wurden nach <b>/data/wal_archive</b> kopiert. Es ist nicht möglich, kleinere Datei zu schreiben, deswegen besteht das Risiko max. 16MB an Daten zu verlieren, wenn der Server stirbt und die WAL Datei noch nicht geschrieben hat. Es gibt allerdings die Möglichkeit einen Timeout zu setzen, nach welchem auf jeden Fall das Segment geschrieben werden soll.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">archive_timeout = <span style="color: #000000;">60</span></pre></div></div>

<p>Hierdurch würden alle 60 Sekunden ein Segment geschrieben werden, auch wenn keine Schreiboperation durchgeführt würde! Das Segment ist dann trotzdem 16MB groß, und mit NULL Daten gefüllt. Es ist also abzuwägen ob und wie hoch der Timeout sein soll.</p>
<p>Grundsätzlich sichere ich die WAL Segmente großer Datenbank auf einen anderen Server, damit das Hauptsystem nicht durch das Backup bzw. den erhöhten Speicherbedarf belastet wird. Einerseits kann das Segment auf ein mit <b>NFS</b> eingehängtes Volumen gespeichert werden, oder es wird mit <b>scp</b> oder <b>rsync</b> kopiert. Der <b>archive_command</b> Aufruf für <b>rsync</b> könnte wie folgt ausehen:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">archive_command = <span style="color: #ff0000;">'rsync --delay-updates --whole-file -ar -e ssh %p postgres@192.168.0.2:/data/wal_archive/%f &lt;/dev/null'</span></pre></div></div>

<p>Die Segmente werden dann automatisch in das Verzeichnis <b>/data/wal_archive</b> auf dem Server <b>192.168.0.2</b> kopiert. Es sollte allerdings ein SSH-Key ohne Passwort auf dem Zielsystem für den Benutzer <b>postgres</b> hinterlegt sein.</p>
<p>Für die eigentliche Sicherung muss nur nach das Verzeichnis <b>/data/wal_archive</b> auf dem Server <b>192.168.0.2</b> eingetragen werden. Zugegeben, diese Art von Datensicherung verbraucht viel Speicherplatz, da die Festplattenpreise allerdings sehr niedrig sind und das Datenbanksystem kaum belastet wird, rechtfertigt sich der hohe Speicherbedarf durchaus.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.treibsand.com/2009/06/19/backup-einer-grosen-postgresql-datenbank/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PostgreSQL Replikation</title>
		<link>http://www.treibsand.com/2009/06/16/postgresql-replikation/</link>
		<comments>http://www.treibsand.com/2009/06/16/postgresql-replikation/#comments</comments>
		<pubDate>Tue, 16 Jun 2009 09:59:30 +0000</pubDate>
		<dc:creator>Toast</dc:creator>
				<category><![CDATA[Unix]]></category>
		<category><![CDATA[Datenbank]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[Replikation]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://www.treibsand.com/?p=312</guid>
		<description><![CDATA[Replikation bei Datenbanken ist ein ziemlich umfangreiches Thema. PostgreSQL bietet in der Distribution leider keine mitgelieferte Möglichkeit Datenbanken in einem Master-Slave Setup zu replizieren. Da ist man auf Tools wie Slony-I oder die Skytools angewiesen. Da Slony-I sehr umfangreich und nicht gerade einfach zu konfigurieren ist, habe ich mir die Skytools bzw. londiste näher angeschaut, [...]]]></description>
			<content:encoded><![CDATA[<p>Replikation bei Datenbanken ist ein ziemlich umfangreiches Thema. PostgreSQL bietet in der Distribution leider keine mitgelieferte Möglichkeit Datenbanken in einem Master-Slave Setup zu replizieren. Da ist man auf Tools wie <a href="http://www.slony.info/">Slony-I</a> oder die <a href="https://developer.skype.com/SkypeGarage/DbProjects/SkyTools">Skytools</a> angewiesen. Da Slony-I sehr umfangreich und nicht gerade einfach zu konfigurieren ist, habe ich mir die Skytools bzw. londiste näher angeschaut, und muss sagen, dass es wirklich hervorragend funktioniert.</p>
<p><span id="more-312"></span><br />
Die Skytools sind von Skype, und können auf der <a href="http://pgfoundry.org/">PgFoundry</a> Seite gefunden werden.  Als Beispiel nehmen wir eine einfache Datenbank mit nur einer Tabelle&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">SEQUENCE</span> test_seq <span style="color: #993333; font-weight: bold;">START</span> <span style="color: #993333; font-weight: bold;">WITH</span> <span style="color: #cc66cc;">1</span>;
<span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> test <span style="color: #66cc66;">&#40;</span>
  id int4 <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span><span style="color: #66cc66;">,</span> 
  txt text
<span style="color: #66cc66;">&#41;</span>;</pre></div></div>

<p>Jetzt brauchen wir noch ein paar Datensätze&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> test <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #993333; font-weight: bold;">NEXTVAL</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'test_seq'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'bla'</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> test <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #993333; font-weight: bold;">NEXTVAL</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'test_seq'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'blub'</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> test <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #993333; font-weight: bold;">NEXTVAL</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'test_seq'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'test text'</span><span style="color: #66cc66;">&#41;</span>;</pre></div></div>

<p>Nachdem alle Tabelle angelegt ist, sollte die Datenbank auf dem Slave Server erstellt werden. Danach können die Inhalte mit einem Dump initial übernommen werden&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ pg_dump <span style="color: #660033;">-U</span> postgres <span style="color: #660033;">-s</span> <span style="color: #7a0874; font-weight: bold;">test</span> <span style="color: #000000; font-weight: bold;">|</span> psql <span style="color: #660033;">-h</span> <span style="color: #000000; font-weight: bold;">&lt;</span>IP-VON-SLAVE<span style="color: #000000; font-weight: bold;">&gt;</span> <span style="color: #660033;">-U</span> postgres <span style="color: #7a0874; font-weight: bold;">test</span></pre></div></div>

<p>Damit londiste laufen kann, brauchen wir einen Ticker, dieser muss auf dem Master-Server laufen. Die Konfiguration kann wie folgt aussehen (hier die Datei /etc/ticker.ini):</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#91;</span>pgqadm<span style="color: #7a0874; font-weight: bold;">&#93;</span>
job_name = ticker
db = <span style="color: #007800;">dbname</span>=<span style="color: #7a0874; font-weight: bold;">test</span> 
maint_delay_min = <span style="color: #000000;">1</span>
loop_delay = <span style="color: #000000;">0.5</span>
logfile = <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>log.<span style="color: #000000; font-weight: bold;">%</span><span style="color: #7a0874; font-weight: bold;">&#40;</span>job_name<span style="color: #7a0874; font-weight: bold;">&#41;</span>s
pidfile = <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>pid.<span style="color: #000000; font-weight: bold;">%</span><span style="color: #7a0874; font-weight: bold;">&#40;</span>job_name<span style="color: #7a0874; font-weight: bold;">&#41;</span>s
use_skylog = <span style="color: #000000;">0</span>
connection_lifetime = <span style="color: #000000;">21</span>
queue_refresh_period = <span style="color: #000000;">10</span></pre></div></div>

<p>Danach kann der Ticker gestartet werden&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ pgqadm.py <span style="color: #660033;">-d</span> <span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>ticker.ini ticker</pre></div></div>

<p>Als nächstes brauchen wir noch für londiste ebenfalls eine Konfigurationsdatei (hier /etc/londiste.ini):</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #66cc66;">&#91;</span>londiste<span style="color: #66cc66;">&#93;</span>
job_name <span style="color: #66cc66;">=</span> test_to_subcriber
provider_db <span style="color: #66cc66;">=</span> dbname<span style="color: #66cc66;">=</span>test port<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">5432</span> host<span style="color: #66cc66;">=&lt;</span>IP<span style="color: #66cc66;">-</span>VON<span style="color: #66cc66;">-</span>MASTER<span style="color: #66cc66;">&gt;</span>
subscriber_db <span style="color: #66cc66;">=</span> dbname<span style="color: #66cc66;">=</span>test port<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">5432</span> host<span style="color: #66cc66;">=&lt;</span>IP<span style="color: #66cc66;">-</span>VON<span style="color: #66cc66;">-</span>SLAVE<span style="color: #66cc66;">&gt;</span>
pgq_queue_name <span style="color: #66cc66;">=</span> londiste<span style="color: #66cc66;">.</span>replika
logfile <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">/</span>tmp<span style="color: #66cc66;">/</span>%<span style="color: #66cc66;">&#40;</span>job_name<span style="color: #66cc66;">&#41;</span>s<span style="color: #66cc66;">.</span>log
pidfile <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">/</span>tmp<span style="color: #66cc66;">/</span>%<span style="color: #66cc66;">&#40;</span>job_name<span style="color: #66cc66;">&#41;</span>s<span style="color: #66cc66;">.</span>pid</pre></div></div>

<p>Die londiste Konfigurationsdatei muss auf beiden Server sein, damit die Replikation funktioniert. Auf dem Slave-System kann londiste nun installiert werden</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ londiste.py <span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>londiste.ini provider <span style="color: #c20cb9; font-weight: bold;">install</span>
$ londiste.py <span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>londiste.ini subscriber <span style="color: #c20cb9; font-weight: bold;">install</span>
$ londiste.py <span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>londiste.ini provider add <span style="color: #7a0874; font-weight: bold;">test</span>
$ londiste.py <span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>londiste.ini subscriber add <span style="color: #7a0874; font-weight: bold;">test</span>
$ londiste.py <span style="color: #660033;">-d</span> <span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>londiste.ini replay</pre></div></div>

<p>Londiste läuft nun im Hintergrund als Daemon und sollte alle neuen Daten sofort auf den Slave replizieren.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.treibsand.com/2009/06/16/postgresql-replikation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Volltextsuche mit PostgreSQL</title>
		<link>http://www.treibsand.com/2009/01/26/volltextsuche-mit-postgresql/</link>
		<comments>http://www.treibsand.com/2009/01/26/volltextsuche-mit-postgresql/#comments</comments>
		<pubDate>Mon, 26 Jan 2009 16:11:25 +0000</pubDate>
		<dc:creator>Toast</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[tsearch2]]></category>
		<category><![CDATA[Volltextsuche]]></category>

		<guid isPermaLink="false">http://www.treibsand.com/2009/01/26/volltextsuche-mit-postgresql/</guid>
		<description><![CDATA[Viele Programmierer waren schon frustriert, weil eine Volltextsuche benötigt wurde. Welche Engine ist die Beste? Warum braucht die Engine einen eigenen Dienst? Wieso brauch ich dafür eine zweite Datenbank? Seit PostgreSQL 8.3 ist tsearch2 direkt integriert. Bei tsearch2 handelt es sich um eine Volltextsuche, welche direkt in PostgreSQL angesprochen wird. Dadurch ist es möglich, die [...]]]></description>
			<content:encoded><![CDATA[<p>Viele Programmierer waren schon frustriert, weil eine<br />
Volltextsuche benötigt wurde. Welche Engine ist die Beste? Warum braucht die<br />
Engine einen eigenen Dienst? Wieso brauch ich dafür eine zweite Datenbank?</p>
<p><span id="more-236"></span><br />
Seit PostgreSQL 8.3 ist tsearch2 direkt integriert. Bei tsearch2 handelt<br />
es sich um eine Volltextsuche, welche direkt in PostgreSQL angesprochen wird.<br />
Dadurch ist es möglich, die Informationen für die Suche direkt in die Tabellen einzubetten.</p>
<p>Tsearch2 liefert einige neue Datentypen und Funktionen, mit welchen gearbeitet werden<br />
kann. Ein Datentyp ist z.B. tsvector, welchen man direkt testen kann&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #ff0000;">'Der erste String zum testen '</span>::tsvector;
               tsvector                
<span style="color: #808080; font-style: italic;">---------------------------------------</span>
 <span style="color: #ff0000;">'Der'</span> <span style="color: #ff0000;">'zum'</span> <span style="color: #ff0000;">'erste'</span> <span style="color: #ff0000;">'String'</span> <span style="color: #ff0000;">'testen'</span>
<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">1</span> <span style="color: #993333; font-weight: bold;">ROW</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>Als Ergebnis bekommen wir alle Wörter des Strings. Wörter, welche<br />
doppelt im Text stehen, werden nur einmal angezeigt, was durchaus auch<br />
Sinn macht.</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #ff0000;">'Der erste String zum testen und testen '</span>::tsvector;
               tsvector                   
<span style="color: #808080; font-style: italic;">---------------------------------------------</span>
 <span style="color: #ff0000;">'Der'</span> <span style="color: #ff0000;">'und'</span> <span style="color: #ff0000;">'zum'</span> <span style="color: #ff0000;">'erste'</span> <span style="color: #ff0000;">'String'</span> <span style="color: #ff0000;">'testen'</span>
<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">1</span> <span style="color: #993333; font-weight: bold;">ROW</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>Um das ganze mal etwas praktischer anzugehen, legen wir uns als erstes<br />
eine Tabelle an, welche Texte enthalten soll:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> messages <span style="color: #66cc66;">&#40;</span>
	id int4<span style="color: #66cc66;">,</span>
	message text<span style="color: #66cc66;">&#41;</span>;</pre></div></div>

<p>Und wir brauchen auch noch Inhalte&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> messages <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'1'</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'Dies ist eine Testnachricht'</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> messages <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'2'</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'Dumdidum Nachricht'</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> messages <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'3'</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'Ich bin ein Blindtext'</span><span style="color: #66cc66;">&#41;</span>;</pre></div></div>

<p>Jetzt haben wir ein Paar Daten in der Tabelle, aber noch keine Möglichkeit<br />
einen Volltextindex zu speichern. Den Index können wir wie folgt anlegen:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">ALTER</span> <span style="color: #993333; font-weight: bold;">TABLE</span> messages <span style="color: #993333; font-weight: bold;">ADD</span> <span style="color: #993333; font-weight: bold;">COLUMN</span> idxFTI tsvector;</pre></div></div>

<p>Um das Feld die neue Spalte initial zu füllen sollte man wie folgt vorgehen:</p>
<ul>
<li>Tabelle updaten</li>
<li>vacuum full analyze ausführen</li>
<li>Index erstellen</li>
<li>nochmal vacuum full analyze ausführen</li>
</ul>
<p>Als erstes erzeugen wir den Volltextindex aus der Spalte message und<br />
führen ein Vacuum aus&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">UPDATE</span> messages <span style="color: #993333; font-weight: bold;">SET</span> idxFTI<span style="color: #66cc66;">=</span>to_tsvector<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'default'</span><span style="color: #66cc66;">,</span>message<span style="color: #66cc66;">&#41;</span>;
VACUUM <span style="color: #993333; font-weight: bold;">FULL</span> ANALYZE;</pre></div></div>

<p>Wenn z.B. mehrere Spalten in den Volltextindex aufgenommen werden sollen,<br />
dann könnte man es wie folgt machen&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">UPDATE</span> messages
  <span style="color: #993333; font-weight: bold;">SET</span> idxFTI<span style="color: #66cc66;">=</span>to_tsvector<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'default'</span><span style="color: #66cc66;">,</span><span style="color: #993333; font-weight: bold;">COALESCE</span><span style="color: #66cc66;">&#40;</span>message<span style="color: #66cc66;">,</span><span style="color: #ff0000;">''</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">||</span><span style="color: #ff0000;">' '</span><span style="color: #66cc66;">||</span> <span style="color: #993333; font-weight: bold;">COALESCE</span><span style="color: #66cc66;">&#40;</span>andereSpalte<span style="color: #66cc66;">,</span><span style="color: #ff0000;">''</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;
VACUUM <span style="color: #993333; font-weight: bold;">FULL</span> ANALYZE;</pre></div></div>

<p>Jetzt erzeugen wir einen normalen Index auf der Spalte idxFTI&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">INDEX</span> idxFTI_idx <span style="color: #993333; font-weight: bold;">ON</span> messages <span style="color: #993333; font-weight: bold;">USING</span> gist<span style="color: #66cc66;">&#40;</span>idxFTI<span style="color: #66cc66;">&#41;</span>;
VACUUM <span style="color: #993333; font-weight: bold;">FULL</span> ANALYZE;</pre></div></div>

<p>Im Prinzip kann man schon jetzt per Volltext suchen. Eine Suche nach<br />
dem Wort &#8220;ein&#8221; liefert z.B.</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SELECT</span> id<span style="color: #66cc66;">,</span> message <span style="color: #993333; font-weight: bold;">FROM</span> messages <span style="color: #993333; font-weight: bold;">WHERE</span> idxfti @@ <span style="color: #ff0000;">'ein'</span>::tsquery;
    id <span style="color: #66cc66;">|</span>           message           
<span style="color: #808080; font-style: italic;">-------+-----------------------------</span>
     <span style="color: #cc66cc;">1</span> <span style="color: #66cc66;">|</span> Dies ist eine Testnachricht
     <span style="color: #cc66cc;">3</span> <span style="color: #66cc66;">|</span> Ich bin ein Blindtext
<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">2</span> <span style="color: #993333; font-weight: bold;">ROWS</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>Wie aber erzeugen wir den Inhalt von idxFTI, wenn ein neuer<br />
Datensatz eingetragen wird? Hier helfen Trigger und Stored Procedures&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">OR</span> <span style="color: #993333; font-weight: bold;">REPLACE</span> <span style="color: #993333; font-weight: bold;">FUNCTION</span> vectorupdate<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
  <span style="color: #993333; font-weight: bold;">RETURNS</span> <span style="color: #993333; font-weight: bold;">TRIGGER</span> <span style="color: #993333; font-weight: bold;">AS</span> $vectorupdate$
<span style="color: #993333; font-weight: bold;">BEGIN</span>
  <span style="color: #993333; font-weight: bold;">UPDATE</span> messages
  <span style="color: #993333; font-weight: bold;">SET</span> idxFTI<span style="color: #66cc66;">=</span>to_tsvector<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'default'</span><span style="color: #66cc66;">,</span>message<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">WHERE</span> id<span style="color: #66cc66;">=</span><span style="color: #993333; font-weight: bold;">NEW</span><span style="color: #66cc66;">.</span>id;
&nbsp;
  <span style="color: #993333; font-weight: bold;">RETURN</span> <span style="color: #993333; font-weight: bold;">NEW</span>;
<span style="color: #993333; font-weight: bold;">END</span>;
$vectorupdate$ <span style="color: #993333; font-weight: bold;">LANGUAGE</span> plpgsql;
&nbsp;
<span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TRIGGER</span> tgr_vectorupdate AFTER <span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">OR</span> <span style="color: #993333; font-weight: bold;">UPDATE</span> <span style="color: #993333; font-weight: bold;">ON</span> messages
  <span style="color: #993333; font-weight: bold;">FOR</span> EACH <span style="color: #993333; font-weight: bold;">ROW</span> <span style="color: #993333; font-weight: bold;">EXECUTE</span> <span style="color: #993333; font-weight: bold;">PROCEDURE</span> vectorupdate<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;</pre></div></div>

<p>Wenn jetzt ein neuer Datensatz eingetragen bzw. verändert wird, dann<br />
wir auch automatisch der Volltextindex aktualisiert.</p>
<p>Natürlich war dies nur ein kurzer Abriss von tsearch2, für den<br />
vollen Einblick muss ich auf die <a href="http://www.sai.msu.su/~megera/postgres/gist/tsearch/V2/"><br />
Dokumentation</a> verweisen.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.treibsand.com/2009/01/26/volltextsuche-mit-postgresql/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
	</channel>
</rss>

