<?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>MoMolog &#187; Postgresql</title>
	<atom:link href="http://momolog.info/category/postgresql/feed/" rel="self" type="application/rss+xml" />
	<link>http://momolog.info</link>
	<description>MoMolog aus Berlin stellt sich vor. Projekte, Ideen, Referenzen.</description>
	<lastBuildDate>Sun, 18 Jul 2010 22:13:17 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Atomares Einfügen in PostgreSQL &#124; Teil 2</title>
		<link>http://momolog.info/2009/06/24/atomares-einfugen-in-postgresql-teil-2/</link>
		<comments>http://momolog.info/2009/06/24/atomares-einfugen-in-postgresql-teil-2/#comments</comments>
		<pubDate>Wed, 24 Jun 2009 19:59:24 +0000</pubDate>
		<dc:creator>aljoscha</dc:creator>
				<category><![CDATA[Postgresql]]></category>

		<guid isPermaLink="false">http://momolog.info/?p=113</guid>
		<description><![CDATA[Die im vorletzten Artikel vorgestellte Lösung hat den Nachteil, den ganzen Table my_table zu locken. Das ist dann ein Problem, wenn criterion mittels unique constraint eindeutig gemacht wird und nach der Funktion eine zeitaufwendige Funktion (z.B. eine Suche) in derselben Transaktion folgt: Dann warten nämlich alle Prozesse, die ein findOrCreate machen wollen, unabhängig mit welchem [...]]]></description>
			<content:encoded><![CDATA[<p>Die im vorletzten Artikel vorgestellte Lösung hat den Nachteil, den ganzen Table <code>my_table</code> zu locken.<br />
Das ist dann ein Problem, wenn <code>criterion</code> mittels unique constraint eindeutig gemacht wird und nach der Funktion eine zeitaufwendige Funktion (z.B. eine Suche) in derselben Transaktion folgt: Dann warten nämlich alle Prozesse, die ein <code>findOrCreate</code> machen wollen, unabhängig mit welchem Wert für <code>criterion</code>, auf den Abschluss der ersten Transaktion, da erst zu diesem Zeitpunkt sichergestellt werden kann, dass die Spalte wirklich unique ist.</p>
<p>Eigentlich sollte es aber möglich sein, dass parallele Transaktionen mit <em>anderen</em> Werten für <code>criterion</code> unbehelligt ausgeführt werden.<br />
Mit dem folgenden, von Martin Heistermann und Stephan Lüderitz vorgeschlagenen Ansatz, umgeht man dieses Problem elegant:<br />
<pre><pre>
CREATE OR REPLACE FUNCTION findOrCreate(
  IN criterion_in text,
  OUT record_id integer, OUT is_new bool) AS
$$
DECLARE
BEGIN
    INSERT INTO
      my_table (criterion)
    VALUES
      (criterion_in)
    RETURNING id INTO record_id;
    SELECT true INTO is_new;
EXCEPTION
    WHEN unique_violation THEN
        SELECT false, id into is_new, record_id FROM my_table 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WHERE criterion=criterion_in;
END
$$ language plpgsql;
</pre></pre></p>
<p>Wie in <a href="http://www.postgresql.org/files/developer/concurrency.pdf">dieser Präsentation (PDF)</a> beschrieben, läßt PostgreSQL das parallele Einfügen <em>verschiedener</em> Werte mittels <code>findOrCreate</code> zu, zwingt aber bei zwei Transaktionen, die <em>denselben</em> Wert einfügen wollen, die zweite, mit dem Insert auf das Ende der ersten zu warten. </p>
<p>Findet die (potentiell teure) Suche in der Transaktion <em>nach</em> findOrCreate statt, wird diese gar nicht mehr ausgeführt, da findOrCreate per Exception die von der ersten Transaktion neu eingefügte Zeile ermittelt und gleich mit deren Ergebnissen weitermachen kann.</p>
]]></content:encoded>
			<wfw:commentRss>http://momolog.info/2009/06/24/atomares-einfugen-in-postgresql-teil-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Atomares Einfügen in PostgreSQL</title>
		<link>http://momolog.info/2009/05/16/atomares-einfugen-in-postgresql/</link>
		<comments>http://momolog.info/2009/05/16/atomares-einfugen-in-postgresql/#comments</comments>
		<pubDate>Sat, 16 May 2009 15:31:26 +0000</pubDate>
		<dc:creator>aljoscha</dc:creator>
				<category><![CDATA[Postgresql]]></category>

		<guid isPermaLink="false">http://momolog.info/?p=15</guid>
		<description><![CDATA[Oft steht man vor dem Problem, einen Datensatz anhand eines Kriteriums zu finden bzw. ihn, falls nicht vorhanden, einzufügen. Bei derartigen Operationen ist es wichtig darauf zu achten, dass nicht mehrere Prozesse, die quasi gleichzeitig diesen Datensatz suchen, eine race condition hervorrufen. Hier eine Lösung mittels stored procedure für postgresql. Dabei wird eine race condition [...]]]></description>
			<content:encoded><![CDATA[<p>Oft steht man vor dem Problem, einen Datensatz anhand eines Kriteriums zu finden bzw. ihn, falls nicht vorhanden, einzufügen. Bei derartigen Operationen ist es wichtig darauf zu achten, dass nicht mehrere Prozesse, die quasi gleichzeitig diesen Datensatz suchen, eine <a href="http://de.wikipedia.org/wiki/Race_Condition">race condition</a> hervorrufen.<br />
Hier eine Lösung mittels stored procedure für postgresql. Dabei wird eine race condition zwischen Suche und Einfügen vermieden und nur minimales Locking gebraucht:<br />
<pre><pre>
CREATE OR REPLACE FUNCTION findOrCreate(
&nbsp;&nbsp;IN criterion_in text, 
&nbsp;&nbsp;OUT id int, OUT is_new bool) AS 
$$
DECLARE 
BEGIN
&nbsp;&nbsp;LOCK TABLE my_table;
&nbsp;&nbsp;SELECT false, id FROM my_table WHERE criterion=criterion_in INTO is_new, id;

&nbsp;&nbsp;IF id IS NULL THEN
&nbsp;&nbsp;&nbsp;&nbsp;INSERT INTO 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my_table (criterion) 
&nbsp;&nbsp;&nbsp;&nbsp;VALUES 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(criterion_in) 
&nbsp;&nbsp;&nbsp;&nbsp;RETURNING id INTO id;
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;SELECT true INTO is_new;
&nbsp;&nbsp;END IF;

&nbsp;&nbsp;RETURN;
END
$$ language plpgsql;
</pre></pre><br />
Man beachte die praktischen OUT-Parameter, die es ermöglichen, diese Funktion wie folgt aufzurufen:<br />
<pre><pre>
SELECT id, is_new FROM findOrCreate(criterion);
</pre></pre><br />
Rückgabewerte sind <code>id</code> und <code>is_new</code>, die einem die Datenbank-Id angeben, und ob diese neu angelegt wurde.</p>
<p>Der Table-Lock wird beim Beenden der Funktion (die immer implizit eine Transaktion ist) automatisch beendet.</p>
]]></content:encoded>
			<wfw:commentRss>http://momolog.info/2009/05/16/atomares-einfugen-in-postgresql/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>hstore magic</title>
		<link>http://momolog.info/2007/04/17/hstore-magic/</link>
		<comments>http://momolog.info/2007/04/17/hstore-magic/#comments</comments>
		<pubDate>Tue, 17 Apr 2007 10:08:54 +0000</pubDate>
		<dc:creator>aljoscha</dc:creator>
				<category><![CDATA[Postgresql]]></category>

		<guid isPermaLink="false">http://momolog.info/2007/04/17/hstore-magic/</guid>
		<description><![CDATA[A lot of nice things can be done with postgresql&#8217;s hstore type. They are a nice way to store flags, for example, and by providing an aggregate function to sum them up, one can easily compute complex unions of properties. First we define an aggregate function to sum postgresql hstores, straightforward as this: CREATE AGGREGATE [...]]]></description>
			<content:encoded><![CDATA[<p>A lot of nice things can be done with <a href="http://www.sai.msu.su/~megera/wiki/Hstore">postgresql&#8217;s hstore type</a>.</p>
<p>They are a nice way to store flags, for example, and by providing an aggregate function to sum them up, one can easily compute complex unions of properties.</p>
<p>First we define an aggregate function to sum postgresql hstores, straightforward as this:</p>
<p><pre><pre>
CREATE AGGREGATE sum(
&nbsp;&nbsp;sfunc&nbsp;&nbsp;&nbsp;&nbsp; = hs_concat,
&nbsp;&nbsp;basetype&nbsp;&nbsp;= hstore,
&nbsp;&nbsp;stype&nbsp;&nbsp;&nbsp;&nbsp; = hstore,
&nbsp;&nbsp;initcond&nbsp;&nbsp;= &#039;&#039;
);
</pre></pre></p>
<p>Allows for beautiful constructs as </p>
<p><pre><pre>
CREATE OR REPLACE FUNCTION array_to_hstore(text[]) RETURNS hstore AS $$
&nbsp;&nbsp;DECLARE
&nbsp;&nbsp;&nbsp;&nbsp;arr&nbsp;&nbsp;&nbsp;&nbsp; text[];
&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;&nbsp;hstore;
&nbsp;&nbsp;BEGIN
&nbsp;&nbsp;&nbsp;&nbsp;SELECT INTO arr $1;

&nbsp;&nbsp;&nbsp;&nbsp;SELECT INTO result sum(key=&gt;1) FROM (
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;select
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;btrim(arr[idx.i]) as key
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;generate_series(1, array_upper(arr,1)) as idx(i)
&nbsp;&nbsp;&nbsp;&nbsp;) as dummy;

&nbsp;&nbsp;&nbsp;&nbsp;RETURN result;

&nbsp;&nbsp;END
$$ LANGUAGE plpgsql;
</pre></pre></p>
<p>Now what can be done with that? For example we can turn comma separated lists into hstores:</p>
<p><pre><pre>
mydb=&gt; SELECT array_to_hstore(string_to_array(&#039;a, b, c, a&#039;, &#039;,&#039;));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array_to_hstore&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-------------------------------------------
 &quot;a&quot;=&gt;&quot;1&quot;, &quot;b&quot;=&gt;&quot;1&quot;, &quot;c&quot;=&gt;&quot;1&quot;
(1 Zeile)
</pre></pre></p>
]]></content:encoded>
			<wfw:commentRss>http://momolog.info/2007/04/17/hstore-magic/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
