<?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>Inovia Blog &#187; postgres</title>
	<atom:link href="http://blog.inovia.fr/tag/postgres/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.inovia.fr</link>
	<description></description>
	<lastBuildDate>Tue, 03 Jul 2012 13:41:13 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
<xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" />
		<item>
		<title>Auto partitioning in postgresql – Part 2</title>
		<link>http://blog.inovia.fr/auto-partitioning-in-postgresql-%e2%80%93-part-2/</link>
		<comments>http://blog.inovia.fr/auto-partitioning-in-postgresql-%e2%80%93-part-2/#comments</comments>
		<pubDate>Thu, 21 Jul 2011 15:24:21 +0000</pubDate>
		<dc:creator>inovia</dc:creator>
				<category><![CDATA[Databases]]></category>
		<category><![CDATA[db]]></category>
		<category><![CDATA[postgres]]></category>

		<guid isPermaLink="false">http://blog.inovia.fr/?p=136</guid>
		<description><![CDATA[After having created the partitions, now we will create a maintenance function that will help us running queries on every partition. &#160; We saw in the first part how to dynamically create the needed partitions. Just add this function in &#8230; <a href="http://blog.inovia.fr/auto-partitioning-in-postgresql-%e2%80%93-part-2/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<h2>
After having created the partitions, now we will create a maintenance function that will help us running queries on every partition.</h2>
<p>&nbsp;<br />
We <a href="http://blog.inovia.fr/auto-partitioning-on-postgresql-part-1/">saw in the first part</a> how to dynamically create the needed partitions.<br />
Just add this function in Postgresql (via psql for instance) :</p>
<pre class="brush: sql"> CREATE OR REPLACE FUNCTION run_on_partitions(text,text) RETURNS INTEGER AS $$
DECLARE
partition RECORD;
tablename TEXT = $1;
sql TEXT = $2;
sqlReplaced TEXT;
BEGIN
tablename := tablename || &#039;%p&#039;;
FOR partition IN SELECT relname::text as rel FROM pg_class WHERE relname::text LIKE tablename AND relkind = &#039;t&#039; ORDER BY relname LOOP
sqlReplaced := replace(sql, &#039;&#039;,partition.rel);
RAISE NOTICE &#039;Executing: %&#039;, sqlReplaced;
EXECUTE  sqlReplaced;
END LOOP;
RETURN 1;
END;
$$ LANGUAGE plpgsql;</pre>
<p>&nbsp;<br />
This function is really useful. To call it, simply do:</p>
<pre class="brush: sql"> SELECT run_on_partitions(&#039;tablename&#039;,&#039;CREATE INDEX _idx ON  USING btree(name)&#039;);</pre>
<p>&nbsp;<br />
The tag &lt;PARTITION&gt; will be replaced by the name of the partition derived from the master table ‘tablename’. We can now create indexes, primary keys on each table&#8230;without having to run the query against each table by hand.<br />
Let’s create a full text search index on these items:</p>
<pre class="brush: sql">SELECT run_on_partitions(&#039;tablename&#039;,&#039;CREATE INDEX _fts_idx ON  USING gin (to_tsvector(name::text || &#039;&#039; &#039;&#039;::text) || description));&#039;);</pre>
<p> &nbsp;<br />
The search time has now been greatly improved.<br />
&nbsp;<br />
Yeepa!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.inovia.fr/auto-partitioning-in-postgresql-%e2%80%93-part-2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Auto partitioning on Postgresql &#8211; Part 1</title>
		<link>http://blog.inovia.fr/auto-partitioning-on-postgresql-part-1/</link>
		<comments>http://blog.inovia.fr/auto-partitioning-on-postgresql-part-1/#comments</comments>
		<pubDate>Mon, 27 Jun 2011 13:15:57 +0000</pubDate>
		<dc:creator>inovia</dc:creator>
				<category><![CDATA[Databases]]></category>
		<category><![CDATA[db]]></category>
		<category><![CDATA[postgres]]></category>

		<guid isPermaLink="false">http://blog.inovia.fr/?p=63</guid>
		<description><![CDATA[We will share a simple approach to migrate existing tables to partitioned versions of them with Postgresql. The partitions will be created on demand with just a few lines of codes. It is useful during off-line migration, and can be &#8230; <a href="http://blog.inovia.fr/auto-partitioning-on-postgresql-part-1/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<h2>We will share a simple approach to migrate existing tables to partitioned versions of them with Postgresql.<br />
The partitions will be created on demand with just a few lines of codes. It is useful during off-line migration, and can be used in production with applications that don’t do so much INSERT.</h2>
<h3>Approach</h3>
<p>Let’s say you want to partition a table based on time period.<br />
In Postgres, we handle partitioning with inheritance. You will have a master table, used to regroup the different partitions, and one table per partition. I let you read the excellent Postgres documentation about this: <a rel="no-follow" href="http://www.postgresql.org/docs/current/static/ddl-partitioning.html" target="_blank">http://www.postgresql.org/docs/current/static/ddl-partitioning.html</a></p>
<p>As you can see, there is a lot of tedious work to create partitions, tables, indexes&#8230; Here we provide you a non optimal solution in terms of insert performance, but definitely more practical in terms of risks and time to settle than the method presented in the manual.</p>
<p>I will show you how to conduct it in a simple case and simplify a bit the manual operation you need to do. From this, you’ll be able to build your own solution.<br />
We got a large fact table called tablename. There is a column on this table called period which can have values like 2011_01 which means January of 2011.<br />
We will create one partition per period. So we will create the tables:<br />
- tablename_2010_01p<br />
- tablename_2010_02p<br />
- tablename_2010_03p<br />
&#8230;</p>
<p>The p at the end helps us detecting that this object is a partition. I admit there is a large space to improve it.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h3>Create the master table</h3>
<pre class="brush: sql">

-- Create the master table tablename_with_partition:
-- You should use the same exact schema as the one from the non partitioned table.
CREATE TABLE tablename_with_partition
(
id integer NOT NULL DEFAULT nextval(&#039;tablename&#039;::regclass),
&quot;name&quot; character varying(150) NOT NULL,
description text NOT NULL,
period character varying(10) NOT NULL
CONSTRAINT tablename_with_partition_pkey PRIMARY KEY (id)
) WITH ( OIDS=FALSE);
</pre>
<p>&nbsp;</p>
<h3>Auto partition creation during insert</h3>
<pre class="brush: sql">

-- Attach a magic function to the insert of this table:
CREATE OR REPLACE FUNCTION create_partition_and_insert()
RETURNS trigger AS
$BODY$
DECLARE
partition VARCHAR(25);
BEGIN
partition := TG_RELNAME || &#039;_&#039; || NEW.period || ‘p’;
IF NOT EXISTS(SELECT relname FROM pg_class WHERE relname=partition) THEN
RAISE NOTICE &#039;A partition has been created %&#039;,partition;
EXECUTE &#039;CREATE TABLE &#039; || partition || &#039; (check (period = &#039;&#039;&#039; || NEW.period || &#039;&#039;&#039;)) INHERITS (&#039; || TG_RELNAME || &#039;);&#039;;
END IF;
EXECUTE &#039;INSERT INTO &#039; || partition || &#039; SELECT(&#039; || TG_RELNAME || &#039; &#039; || quote_literal(NEW) || &#039;).*;&#039;;
RETURN NULL;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
</pre>
<p>This function will try to insert in the correct partition and creates it if it doesn’t exist. This approach is not the most efficient, but if you got less than 20M records, it works definitely fine.<br />
Here we attach the function defined earlier to the insert operation on tablename_with_partitions:</p>
<pre class="brush: sql">

CREATE TRIGGER tablename_insert_trigger
BEFORE INSERT ON tablename_wtih_partition
FOR EACH ROW EXECUTE PROCEDURE create_partition_and_insert();
</pre>
<p>Notice that I didn’t named the trigger with the name “tablename_with_partitions_insert_trigger”. It is because I planned to substitute the partitionned master table and the old non partionned version later on.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h3>Migrate the data</h3>
<pre class="brush: sql">

-- Copy data from the non partitioned to the partitioned version:
INSERT INTO tablename_with_partition SELECT * tablename;
</pre>
<p>It can take a while. But it is a nice approach to do this way.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h3>Testing everything is fine</h3>
<p>Let’s check everything is ok:<br />
- “SELECT count(*) FROM tablename_2010_1;”: you got proper data in one partition.<br />
- “SELECT count(*) FROM tablename_with_partition;” returns the sum of all the elements in the partition<br />
- “SELECT count(*) FROM ONLY tablename_with_partition;” returns 0. It is normal we didn’t insert one line of data in the master table.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h3>What’s next ?</h3>
<p>If everything is fine, we are almost done. We’ll need to build the indexes and substitute tablename by tablename_with_partition.<br />
We’ll see this in the next article by creating a smart function that can execute on every partition an arbitrary SQL command.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.inovia.fr/auto-partitioning-on-postgresql-part-1/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Page Caching using apc
Object Caching 338/338 objects using apc

Served from: blog.inovia.fr @ 2013-05-21 17:22:52 -->