Re: partitioning / rules - strange behavior

From: Tomas Vondra <tv(at)fuzzy(dot)cz>
To:
Cc: "pgsql-general(at)postgresql(dot)org" <pgsql-general(at)postgresql(dot)org>
Subject: Re: partitioning / rules - strange behavior
Date: 2007-02-06 20:28:49
Message-ID: 45C8E501.8020803@fuzzy.cz
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

> If there´s only the insert_8500000 RULE then everything works as expected - the
> insert prints "INSERT 0 0", the row is inserted into the correct partition
> which is sessions_8500000 - I can fetch it using either
>
> SELECT * FROM sessions WHERE id = currval('sessions_id_seq');
>
> or direcly by
>
> SELECT * FROM sessions_8500000 WHERE id = currval('sessions_id_seq');
>
> When I create the next next rule (insert_9000000 for ids between 9000000 and
> 9499999) it stops working - it prints "INSERT 0 0" just as before, everything
> seems fine, but the row disappears - it's not available .
>
> I'm not sure about the query plans, but I think I've checked that and everything
> seemed ok - all the partitions were used as far as I remember. But this
> shouldn't be a problem as we have not reached the 9000000 limit yet (so the new
> partition is not used at all). And we've tried to restart the PostgreSQL as the
> last hope, yesterday, so there really should be no old plans.
>
> I don't have an access to the production database (I have not been able to
> simulate this on the development/testing system) - I'll play with that at night
> (european time). I'll try to drop / recreate the partition (I've tried to
> recreate only the RULEs, not the partitions).
>
> Tomas

OK, I did some tests a while ago and the bad news is I still was not
able to fix it. The table structure is this

=======================================================================

db=> \d sessions
Table "public.sessions"
Column | Type |
Modifiers
------------------+-----------------------------+---------------------
id | integer | not null default
nextval('sessions_id_seq'::regclass)
browser_id | integer |
os_id | integer |
arch_id | integer |
language_id | character(2) |
country_id | character(2) |
visitor_id | integer | not null
ip | inet | not null
ip_forward | inet |
session_date | timestamp without time zone | not null default now()
user_agent | character varying(255) |
screen_width | smallint |
screen_height | smallint |
screen_bit_depth | smallint |
javascript | boolean | default false
browser_minor | character varying(16) |
browser_major | character varying(16) |
referer | text |
last_action | integer | not null default 0
Indexes:
"sessions_pkey" PRIMARY KEY, btree (id)
Check constraints:
... some foreign keys, not important here ...
Rules:
insert_8500000 AS
ON INSERT TO sessions
WHERE new.id >= 8500000 AND new.id <= 8999999 DO INSTEAD INSERT INTO
sessions_8500000 (id, browser_id, os_id, arch_id, language_id,
country_id, visitor_id, ip, ip_forward, session_date, user_agent,
screen_width, screen_height, screen_bit_depth, javascript,
browser_minor, browser_major, referer, last_action)
VALUES (new.id, new.browser_id, new.os_id, new.arch_id,
new.language_id, new.country_id, new.visitor_id, new.ip, new.ip_forward,
new.session_date, new.user_agent, new.screen_width, new.screen_height,
new.screen_bit_depth, new.javascript, new.browser_minor,
new.browser_major, new.referer, new.last_action)

=======================================================================

We're using sequence to generate the sessions(id) value, but that should
not be a problem - with the structure / rules everything works fine (the
current value in sessions_id_seq is about 8700000 so the values are
inserted into the sessions_8500000 partition).

The I create the 'next partition' for values between 9000000 and 9499999
using

=======================================================================

CREATE TABLE sessions_9000000 (
CHECK (id BETWEEN 9000000 AND 9499999),
PRIMARY KEY (id)
) INHERITS (sessions);

=======================================================================

and everything still seems fine, even the execution plans reflect this
new child table:

=======================================================================

db=> explain select * from sessions;
QUERY PLAN
----------------------------------------------------------------------
Result (cost=0.00..52262.48 rows=1052924 width=775)
-> Append (cost=0.00..52262.48 rows=1052924 width=775)
-> Seq Scan on sessions (cost=0.00..12.00 rows=100 width=775)
-> Seq Scan on sessions_8000000 sessions (cost=0.00..23128.78
rows=500539 width=280)
-> Seq Scan on sessions_8500000 sessions (cost=0.00..6147.60
rows=51230 width=775)
-> Seq Scan on sessions_9000000 sessions (cost=0.00..12.00
rows=100 width=775)

=======================================================================

but one I create a RULE for the new partition, thing go wrong. That is I
execute this (I ommited the list of columns)

=======================================================================

CREATE RULE insert_9000000 AS ON INSERT TO sessions WHERE (id BETWEEN
9000000 AND 9499999) DO INSTEAD INSERT INTO sessions_9000000 ( ... all
the columns in sessions) VALUES ( ... all the columns in sessions
prefixed with 'NEW' ...);

=======================================================================

Now when I do for example

=======================================================================

INSERT INTO sessions(id,visitor_id,ip) VALUES (8900000,0,'127.0.0.1');

=======================================================================

this new row should be inserted into the session_8500000 partition as
the 8900000 is clearly between 8500000 AND 8999999. It even seems
succesfully inserted (no exception, returns INSERT 0 0 as usual), but
once I do

SELECT * FROM sessions WHERE id = 8900000

it returns no rows. Even

SELECT * FROM sessions_8500000 WHERE id = 8900000

returns no rows. Here is the execution plan for the INSERT (the
execution plan for the SELECT can be found above).

=======================================================================

db=> EXPLAIN ANALYZE INSERT INTO sessions(id,visitor_id,ip) VALUES
(8900000,0,'127.0.0.1');
QUERY PLAN
----------------------------------------------------------------------
Result (cost=0.00..0.03 rows=1 width=0) (actual time=0.002..0.002
rows=0 loops=1)
One-Time Filter: ((true IS NOT TRUE) AND (false IS NOT TRUE))
Total runtime: 0.063 ms

Result (cost=0.00..0.03 rows=1 width=0) (actual time=0.012..0.013
rows=1 loops=1)
... some triggers for foreign keys on 'sessions' ...
Total runtime: 0.209 ms

Result (cost=0.00..0.03 rows=1 width=0) (actual time=0.001..0.001
rows=0 loops=1)
One-Time Filter: false
Total runtime: 0.052 ms
(15 rows)

====================================================================

The 'funny' thing is once I drop that new rule (insert_9000000) it
starts working again.

I really don't know how to solve this - today I've tried to drop /
recreate the new _9000000 partitions (which are still empty) but no
luck. Tomorrow I'll restore a fresh backup on a development system, and
try if it 'works' in the same way.

Maybe I'm missing something, but I see nothing wrong in the partitions
and rules. I've taken the current backup (taken at night) and loaded
that at the development system - everything works exactly as expected
with exactly the same set-up. BTW we're using PostgreSQL 8.1.4 (on
Linux) on both machines.

Thanks in advance for all your advices how to fix this, optimally with
as little downtime as possible.

Tomas

In response to

Browse pgsql-general by date

  From Date Subject
Next Message Worky Workerson 2007-02-06 20:39:13 tsearch2 parser configuration
Previous Message Alvaro Herrera 2007-02-06 20:02:36 Re: [HACKERS] getting status transaction error