Thread: Postgres eats up memory when using cursors

Postgres eats up memory when using cursors

From
Denis Perchine
Date:
Hello,

I would like to bring subj to your attention again.
The problem is the following:
I need to have cursor opened for a long time.
I declare a cursor on the table of approx. 1 million rows.
And start fetching data by 1000 rows at each fetch.
Data processing can take quite a long time (3-4 days)
Theoretically postgres process should remain the same in size.
But it grows... In the end of 3rd day it becames 256Mb large!!!!
And this is REAL problem.

Also I would like to mention that this problem was raised by other person
also.

I would like to hear any comments on this issue.

--
Sincerely Yours,
Denis Perchine

----------------------------------
E-Mail: dyp@perchine.com
HomePage: http://www.perchine.com/dyp/
FidoNet: 2:5000/120.5
----------------------------------

Re: Postgres eats up memory when using cursors

From
Tom Lane
Date:
Denis Perchine <dyp@perchine.com> writes:
> I declare a cursor on the table of approx. 1 million rows.
> And start fetching data by 1000 rows at each fetch.
> Data processing can take quite a long time (3-4 days)
> Theoretically postgres process should remain the same in size.
> But it grows... In the end of 3rd day it becames 256Mb large!!!!

Query details please?  You can't expect any results from such a
vague report.

            regards, tom lane

Re: Postgres eats up memory when using cursors

From
Denis Perchine
Date:
On Thursday 01 March 2001 21:33, Tom Lane wrote:
> Denis Perchine <dyp@perchine.com> writes:
> > I declare a cursor on the table of approx. 1 million rows.
> > And start fetching data by 1000 rows at each fetch.
> > Data processing can take quite a long time (3-4 days)
> > Theoretically postgres process should remain the same in size.
> > But it grows... In the end of 3rd day it becames 256Mb large!!!!
>
> Query details please?  You can't expect any results from such a
> vague report.

:-)))
That's right.

declare senders_c cursor for select email, first_name, last_name from senders
order by email

fetch 1000 from senders_c

db=# explain declare senders_c cursor for select email, first_name, last_name
from senders order by email;
NOTICE:  QUERY PLAN:

Index Scan using senders_email_key on senders  (cost=0.00..197005.37
rows=928696 width=36)

db=# \d senders
          Table "senders"
 Attribute  |   Type    | Modifier
------------+-----------+----------
 email      | text      |
 first_name | text      |
 last_name  | text      |
 stamp      | timestamp |
Index: senders_email_key

db=# \d senders_email_key
Index "senders_email_key"
 Attribute | Type
-----------+------
 email     | text
unique btree

That's all. I could not imagine anything more simple...

--
Sincerely Yours,
Denis Perchine

----------------------------------
E-Mail: dyp@perchine.com
HomePage: http://www.perchine.com/dyp/
FidoNet: 2:5000/120.5
----------------------------------

Re: Postgres eats up memory when using cursors

From
Tom Lane
Date:
Denis Perchine <dyp@perchine.com> writes:
> I declare a cursor on the table of approx. 1 million rows.
> And start fetching data by 1000 rows at each fetch.
> Data processing can take quite a long time (3-4 days)
> Theoretically postgres process should remain the same in size.
> But it grows... In the end of 3rd day it becames 256Mb large!!!!

> declare senders_c cursor for select email, first_name, last_name from senders
> order by email

> fetch 1000 from senders_c

> db=# explain declare senders_c cursor for select email, first_name, last_name
> from senders order by email;
> NOTICE:  QUERY PLAN:

> Index Scan using senders_email_key on senders  (cost=0.00..197005.37
> rows=928696 width=36)

> db=# \d senders
>           Table "senders"
>  Attribute  |   Type    | Modifier
> ------------+-----------+----------
>  email      | text      |
>  first_name | text      |
>  last_name  | text      |
>  stamp      | timestamp |
> Index: senders_email_key

> db=# \d senders_email_key
> Index "senders_email_key"
>  Attribute | Type
> -----------+------
>  email     | text
> unique btree

> That's all. I could not imagine anything more simple...

Looks pretty simple to me too; I was expecting that you were doing
expression evaluations or some such.  I cannot reproduce any backend
leakage in this query, either in 7.0.* or current sources.  I did

create table senders (email text, first_name text, last_name text);
\copy senders from 'todo'        -- some junk data
create index sendersi on senders(email);
insert into senders select * from senders;  -- repeat a few times

begin;
explain
declare senders_c cursor for select email, first_name, last_name
from senders order by email;
NOTICE:  QUERY PLAN:

Index Scan using sendersi on senders  (cost=0.00..102.78 rows=2161 width=36)

end;

then made a script file

begin;
declare senders_c cursor for select email, first_name, last_name
from senders order by email;

fetch 10000 from senders_c
\g zzz
fetch backward 10000 from senders_c
\g zzz
fetch 10000 from senders_c
\g zzz
fetch backward 10000 from senders_c
\g zzz
fetch 10000 from senders_c
\g zzz
... repeat a few thousand times ...

end;

Backend memory usage is absolutely rock steady.


Curiously, there does seem to be a leak in psql, or possibly libpq,
when running this script.  It's per-query not per-tuple, so it's
easier to see if you make the fetches shorter:

fetch 100 from senders_c
\g zzz
fetch backward 100 from senders_c
\g zzz

Repeating these like mad, psql grows about 1Kb/sec on my machine.
This occurs with current sources but NOT with 7.0.2 psql.  Peter,
any thoughts about that?

            regards, tom lane

Re: Postgres eats up memory when using cursors

From
Denis Perchine
Date:
> Looks pretty simple to me too; I was expecting that you were doing
> expression evaluations or some such.  I cannot reproduce any backend
> leakage in this query, either in 7.0.* or current sources.  I did
>
> create table senders (email text, first_name text, last_name text);
> \copy senders from 'todo'        -- some junk data
> create index sendersi on senders(email);
> insert into senders select * from senders;  -- repeat a few times
>
> begin;
> explain
> declare senders_c cursor for select email, first_name, last_name
> from senders order by email;
> NOTICE:  QUERY PLAN:
>
> Index Scan using sendersi on senders  (cost=0.00..102.78 rows=2161
> width=36)
>
> end;
>
> then made a script file
>
> begin;
> declare senders_c cursor for select email, first_name, last_name
> from senders order by email;
>
> fetch 10000 from senders_c
> \g zzz
> fetch backward 10000 from senders_c
> \g zzz
> fetch 10000 from senders_c
> \g zzz
> fetch backward 10000 from senders_c
> \g zzz
> fetch 10000 from senders_c
> \g zzz
> ... repeat a few thousand times ...
>
> end;
>
> Backend memory usage is absolutely rock steady.
>
> Curiously, there does seem to be a leak in psql, or possibly libpq,
> when running this script.  It's per-query not per-tuple, so it's
> easier to see if you make the fetches shorter:
>
> fetch 100 from senders_c
> \g zzz
> fetch backward 100 from senders_c
> \g zzz
>
> Repeating these like mad, psql grows about 1Kb/sec on my machine.
> This occurs with current sources but NOT with 7.0.2 psql.  Peter,
> any thoughts about that?

Actually you should also consider that there is really intensive inserts
happend at the same time. Cursor is closed in 3-4 days only...

--
Sincerely Yours,
Denis Perchine

----------------------------------
E-Mail: dyp@perchine.com
HomePage: http://www.perchine.com/dyp/
FidoNet: 2:5000/120.5
----------------------------------

Re: Postgres eats up memory when using cursors

From
Peter Eisentraut
Date:
Tom Lane writes:

> Curiously, there does seem to be a leak in psql, or possibly libpq,
> when running this script.  It's per-query not per-tuple, so it's
> easier to see if you make the fetches shorter:
>
> fetch 100 from senders_c
> \g zzz
> fetch backward 100 from senders_c
> \g zzz
>
> Repeating these like mad, psql grows about 1Kb/sec on my machine.
> This occurs with current sources but NOT with 7.0.2 psql.  Peter,
> any thoughts about that?

Well, here's a memory leak:

Index: print.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/bin/psql/print.c,v
retrieving revision 1.16
diff -c -r1.16 print.c
*** print.c     2001/02/27 08:13:27     1.16
--- print.c     2001/03/01 17:30:00
***************
*** 1116,1121 ****
--- 1116,1122 ----
                free(footers[0]);
                free(footers);
        }
+       free(align);
  }


===snip

This leaks (columns + 1) per query, 4 bytes in your case.  But is has been
there in 7.0 as well.

I couldn't find anything suspicious in the CVS diffs of psql or libpq
since 7.0.

So let's think:  What if you use COPY?  \copy?  Plain SELECT?  What's the
leakage per query cycle (not per second)?  Is it related to the size of
the data?

--
Peter Eisentraut      peter_e@gmx.net       http://yi.org/peter-e/


Re: Postgres eats up memory when using cursors

From
Tom Lane
Date:
Peter Eisentraut <peter_e@gmx.net> writes:
> Tom Lane writes:
>> Repeating these like mad, psql grows about 1Kb/sec on my machine.
>> This occurs with current sources but NOT with 7.0.2 psql.  Peter,
>> any thoughts about that?

> Well, here's a memory leak:

Good catch.  I confirm this stops the leak in my test.

> This leaks (columns + 1) per query, 4 bytes in your case.  But is has been
> there in 7.0 as well.

Ooops, my bad --- repeating my test shows process growth in 7.0 as well.
I had missed it the first time because I'd previously done a plain
"select *", which ballooned the process footprint of psql.  So the
leakage was happening within previously-grabbed memory and wasn't
obvious in "top".

This doesn't seem to actually be related to Denis' problem, but a
leak is a leak ...

            regards, tom lane

Re: Postgres eats up memory when using cursors

From
Denis Perchine
Date:
> > This leaks (columns + 1) per query, 4 bytes in your case.  But is has
> > been there in 7.0 as well.
>
> Ooops, my bad --- repeating my test shows process growth in 7.0 as well.
> I had missed it the first time because I'd previously done a plain
> "select *", which ballooned the process footprint of psql.  So the
> leakage was happening within previously-grabbed memory and wasn't
> obvious in "top".
>
> This doesn't seem to actually be related to Denis' problem, but a
> leak is a leak ...

Is this is the same leak? I mean I do not use psql in any mean...

--
Sincerely Yours,
Denis Perchine

----------------------------------
E-Mail: dyp@perchine.com
HomePage: http://www.perchine.com/dyp/
FidoNet: 2:5000/120.5
----------------------------------

Re: Postgres eats up memory when using cursors

From
Tom Lane
Date:
Denis Perchine <dyp@perchine.com> writes:
>> This doesn't seem to actually be related to Denis' problem, but a
>> leak is a leak ...

> Is this is the same leak? I mean I do not use psql in any mean...

It isn't.

I'm now suspecting that your problem must be related to doing inserts
while a cursor is held open.  Are the inserts done by the same backend,
or a different one?  Could you experiment and see if you can devise a
complete example?  I'm kinda busy right now looking at WAL...

            regards, tom lane

Re: Postgres eats up memory when using cursors

From
Denis Perchine
Date:
> >> This doesn't seem to actually be related to Denis' problem, but a
> >> leak is a leak ...
> >
> > Is this is the same leak? I mean I do not use psql in any mean...
>
> It isn't.
>
> I'm now suspecting that your problem must be related to doing inserts
> while a cursor is held open.  Are the inserts done by the same backend,
> or a different one?

By different ones. This backend just do fetches.

> Could you experiment and see if you can devise a complete example?  I'm
> kinda busy right now looking at WAL...

Inserts are the only operations done besides fetching. This is a complete
example. There are no other actions are taken on this table. Only inserts
made by other backend, and fetches trough only on cursor. I mean that this is
the only backend doing fetches.

--
Sincerely Yours,
Denis Perchine

----------------------------------
E-Mail: dyp@perchine.com
HomePage: http://www.perchine.com/dyp/
FidoNet: 2:5000/120.5
----------------------------------