Обсуждение: Partitionin with check functions

Поиск
Список
Период
Сортировка

Partitionin with check functions

От
fatih ozturk
Дата:
Hi

My problem in partitioning is about using functions in table check constraints.
let me explain it

"

DROP DATABASE partitioning;
\set ON_ERROR_STOP y
CREATE DATABASE partitioning;
ALTER DATABASE partitioning set constraint_exclusion TO true;
\c partitioning
CREATE language plpgsql;
CREATE TABLE mainlog (sel int);
CREATE TABLE mainlog_p0 (CHECK (mod(sel,6)=0)) INHERITS (mainlog);
CREATE TABLE mainlog_p1 (CHECK (mod(sel,6)=1)) INHERITS (mainlog);
CREATE TABLE mainlog_p2 (CHECK (mod(sel,6)=2)) INHERITS (mainlog);
CREATE TABLE mainlog_p3 (CHECK (mod(sel,6)=3)) INHERITS (mainlog);
CREATE TABLE mainlog_p4 (CHECK (mod(sel,6)=4)) INHERITS (mainlog);
CREATE TABLE mainlog_p5 (CHECK (mod(sel,6)=5)) INHERITS (mainlog);

CREATE OR REPLACE FUNCTION trg_mainlog_partitioner() RETURNS TRIGGER AS $$
BEGIN
    IF mod(NEW.sel,6) = 0 THEN INSERT INTO mainlog_p0 VALUES (NEW.*);
    ELSIF mod(NEW.sel,6) = 1 THEN INSERT INTO mainlog_p1 VALUES (NEW.*);
    ELSIF mod(NEW.sel,6) = 2 THEN INSERT INTO mainlog_p2 VALUES (NEW.*);
    ELSIF mod(NEW.sel,6) = 3 THEN INSERT INTO mainlog_p3 VALUES (NEW.*);
    ELSIF mod(NEW.sel,6) = 4 THEN INSERT INTO mainlog_p4 VALUES (NEW.*);
    ELSIF mod(NEW.sel,6) = 5 THEN INSERT INTO mainlog_p5 VALUES (NEW.*);
    END IF;
    RETURN NULL;
END;
$$ language plpgsql;

CREATE TRIGGER trg_mainlog_partitioner BEFORE INSERT ON mainlog FOR EACH ROW execute procedure trg_mainlog_partitioner();

INSERT INTO mainlog(sel) SELECT * FROM generate_series(1,1000);

"
partitioning=# SELECT * from only mainlog;
 sel
-----
(0 rows)

partitioning=# SELECT * from only mainlog_p1;
 sel
-----
   1
   7
  13
  19
  25
  31
.....

it seems tables contains expected datas.

But lets explain queries

partitioning=# explain SELECT * from mainlog where sel=123;
                                  QUERY PLAN                                 
------------------------------------------------------------------------------
 Result  (cost=0.00..58.50 rows=18 width=4)
   ->  Append  (cost=0.00..58.50 rows=18 width=4)
         ->  Seq Scan on mainlog  (cost=0.00..40.00 rows=12 width=4)
               Filter: (sel = 123)
         ->  Seq Scan on mainlog_p0 mainlog  (cost=0.00..3.08 rows=1 width=4)
               Filter: (sel = 123)
         ->  Seq Scan on mainlog_p1 mainlog  (cost=0.00..3.09 rows=1 width=4)
               Filter: (sel = 123)
         ->  Seq Scan on mainlog_p2 mainlog  (cost=0.00..3.09 rows=1 width=4)
               Filter: (sel = 123)
         ->  Seq Scan on mainlog_p3 mainlog  (cost=0.00..3.09 rows=1 width=4)
               Filter: (sel = 123)
         ->  Seq Scan on mainlog_p4 mainlog  (cost=0.00..3.09 rows=1 width=4)
               Filter: (sel = 123)
         ->  Seq Scan on mainlog_p5 mainlog  (cost=0.00..3.08 rows=1 width=4)
               Filter: (sel = 123)
(16 rows)

i am expecting that query planer only scans "mainlog_p3" not the others since mod(123,6)=3 so 123 can only be in "mainlog_p3" table and scaning other tables is waste of time.

What is the problem with my partitioning strategy?
How can i make it fixed and make it working as i expected?
Any suggestions

Thanks for your interest

Note: Forgive me, i can not give real table definitions.

Re: Partitionin with check functions

От
Tom Lane
Дата:
fatih ozturk <ozturkfa@yahoo.com> writes:
> My problem in partitioning is about using functions in table check constraints.

By and large, you can't.  Per the fine manual:

    Keep the partitioning constraints simple, else the planner may not be
    able to prove that partitions don't need to be visited. Use simple
    equality conditions for list partitioning, or simple range tests for
    range partitioning, as illustrated in the preceding examples. A good
    rule of thumb is that partitioning constraints should contain only
    comparisons of the partitioning column(s) to constants using
    B-tree-indexable operators.

In particular, a constraint like "sel=123" is *not* going to lead the
planner to draw any conclusions about the value of "mod(sel,6)".
Now, if you'd written "WHERE mod(sel,6)=3", I think it would draw
the right conclusions.

The underlying issue here is that "a=b" does not imply "f(a)=f(b)"
for all functions f, not even if "=" is known to be a btree equality
operator.  Several of PG's standard datatypes have counterexamples,
so the planner *must* take this seriously.

            regards, tom lane

Re: Partitionin with check functions

От
Harald Fuchs
Дата:
In article <2499.1238420859@sss.pgh.pa.us>,
Tom Lane <tgl@sss.pgh.pa.us> writes:

> In particular, a constraint like "sel=123" is *not* going to lead the
> planner to draw any conclusions about the value of "mod(sel,6)".
> Now, if you'd written "WHERE mod(sel,6)=3", I think it would draw
> the right conclusions.

Yes, it does.  It might be worthwile to use

  WHERE sel=123 AND mod(sel,6)=3

I think you could use a rule to add the mod() condition automatically.

Re: Partitionin with check functions

От
fatih ozturk
Дата:
Thank you

"Yes, it does.  It might be worthwile to use

  WHERE sel=123 AND mod(sel,6)=3

I think you could use a rule to add the mod() condition automatically.
"
this is great idea

But the problem is i did not accomplish to find a way to change query like

     partitioning=# select * from mainlog where sel=22;

to
   
     partitioning=# select * from mainlog where sel=22 and mod(sel,6)=4;


"on select" rules just creates views, dont routes the queries.
I cant use tirggers for selects.
Is there exists a way of changing select query before query plan generated?

Any ideas?

I am very appreciative for your answers and interest.

Thanks

--- On Mon, 3/30/09, Harald Fuchs <hari.fuchs@gmail.com> wrote:

From: Harald Fuchs <hari.fuchs@gmail.com>
Subject: Re: [ADMIN] Partitionin with check functions
To: pgsql-admin@postgresql.org
Date: Monday, March 30, 2009, 4:08 PM

In article <2499.1238420859@sss.pgh.pa.us>,
Tom Lane <tgl@sss.pgh.pa.us> writes:

> In particular, a constraint like "sel=123" is *not* going to lead the
> planner to draw any conclusions about the value of "mod(sel,6)".
> Now, if you'd written "WHERE mod(sel,6)=3", I think it would draw
> the right conclusions.

Yes, it does.  It might be worthwile to use

  WHERE sel=123 AND mod(sel,6)=3

I think you could use a rule to add the mod() condition automatically.


--
Sent via pgsql-admin mailing list (pgsql-admin@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-admin