Thread: PERSISTANT PREPARE (another point of view)

PERSISTANT PREPARE (another point of view)

From
Milan Oparnica
Date:
Hi,<br /><br />We are new to Postgre, actually we are migrating from MICROSOFT DBMS technologies to...hopefully
Postgre.<br/>Our company is involved in ERP business software in Serbia and region, currently counting over 200
clients.Some of them have DB's over 4GB in size.<br /><br />Reason for posting is implementation of PREPARE
statements.<br/>I've read a thread "# PREPARE and stuff PFC" on <font size="2">pgsql-performance 2007-06 list and I do
agreethat it would not gain performance issues.<br /><br />What could we gain by introducing a kind of global prepared
statementarea, is SIMPLICITY of DB DEVELOPMENT AND MAINTENANCE.<br /><br />Here is our point of view:<br /><br />We
havean application layer running over db layer. Application layer consists of classes and interfaces and db layer
containsdata and various data manipulation structures.<br />Application layer calls SQL statements expecting some
datasetsas results (inventory list for instance). What it doesn't care about is HOW is query built (sorting,
conditions,etc.) as long as it returns EXPECTED columns. Application simplly calls EXECUTE <statement>
(<param1>,<param2>...).Developers working application layer do not interfere with developers working on DB
andqueries. Plus MOST queries can be written to be reusable in various situations !!!<br /><br />The idea is: LETS
SEPARATESQL STATEMENTS FROM APPLICATION CODE.<br /><br />This way, we can introduce fine tuning to each of our clients
withouthaving to recompile our application. We can also work on improvements of queries performance and complexity
withoutrecompile of the application layer.<br /><br />Since one company has one set of rules PREPARED statements apply
toevery client connected to that database.<br /><br />Now, instead of preparing statements on each connection request
(andwe use around 900 prepared statements), why couldn't we simply prepare these statements ONCE and keep them in some
globalstorage for future everyday usage.<br /><br />We use this approach for forms & reports creation where Crystal
Reportengine creates outlined report based on static prepared statement.<br /><br />This approach is probably not
suitablefor large db systems with tons of data, but is very efficient in 90% of small and medium business size
databases.<br/><br />Please consider this issue when planning your WISH LIST or hopefully To-do-task-list.<br /><br
/>Illbe glad to here comments on this topic as well.<br /><br />Milan Oparnica<br />MELANY SOFWARE TEAM<br /></font><br
/><hr/>Invite your mail contacts to join your friends list with Windows Live Spaces. It's easy! <a
href="http://spaces.live.com/spacesapi.aspx?wx_action=create&wx_url=/friends.aspx&mkt=en-us"target="_new">Try
it!</a>

Re: PERSISTANT PREPARE (another point of view)

From
Tom Lane
Date:
Milan Oparnica <milan.opa@hotmail.com> writes:
> [ much snipped ]
> What could we gain by introducing a kind of global prepared statement area, is SIMPLICITY of DB DEVELOPMENT AND
MAINTENANCE.
> The idea is: LETS SEPARATE SQL STATEMENTS FROM APPLICATION CODE.

Most people around this project think that the best way to do that is to
push as much logic as you can into server-side stored procedures.  That
gives you every advantage that a persistent-prepared-statement feature
would offer, and more besides:

* you can push procedural logic, as well as SQL, out of the application

* you can improve performance by reducing the number of network round
trips needed to accomplish a multi-SQL-statement task
        regards, tom lane


Re: PERSISTANT PREPARE (another point of view)

From
Steve Midgley
Date:
At 04:31 PM 7/11/2008, pgsql-sql-owner@postgresql.org wrote:
>Date: Fri, 11 Jul 2008 23:31:03 +0000
>From: Milan Oparnica <milan.opa@hotmail.com>
>To: <pgsql-sql@postgresql.org>
>Subject: PERSISTANT PREPARE (another point of view)
>Message-ID: <BLU109-W5078B5ABDE57D183AA6695F8900@phx.gbl>
>[snip]
>What could we gain by introducing a kind of global prepared statement 
>area, is SIMPLICITY of DB DEVELOPMENT AND MAINTENANCE.
>
>Here is our point of view:
>[snip]
>Now, instead of preparing statements on each connection request (and 
>we use around 900 prepared statements), why couldn't we simply prepare 
>these statements ONCE and keep them in some global storage for future 
>everyday usage.

Hi,

What's wrong with using complex views, stored procedures, functions and 
maybe even custom data types to accomplish what you want here? It seems 
like you could build a lot of "prepared statements" using these tools, 
providing your application layer developers with a consistent set of 
interfaces to obtain data that are not tied to the data tables 
themselves. And allowing them to insert/update/manage tables via 
structured interfaces as well.

Am I missing something?

Best,

Steve



Re: PERSISTANT PREPARE (another point of view)

From
Milan Oparnica
Date:
>[snip]> What's wrong with using complex views, stored procedures, functions and> maybe even custom data types to
accomplishwhat you want here?
 

Hi Steve,

Correct me if I’m wrong, but views can not accept parameters, and stored 
procedures require defining sets of custom data types or some other 
complicated ways in order to simply accept some parameters and return 
some recordsets useful to the calling application.

In 90% of cases we simply call same SQL statements with slightly 
different parameters and then pass it to business logic of the program. 
SP's are fine, they allow complex looping, nesting, variable declaration 
etc. but 90% of time we just need a SQL with few parameters and a 
resulting recordsets.

Just try to return SELECT * FROM <table> WHERE <field> LIKE <condition> 
using SP!
You need to define a SET OF <table type> and then populate the result 
into this set consuming both time and memory (it states so in Postgre 
documentation).
You can't write it as a view because it has a <condition> as a parameter.
What’s the best solution having in mind that this query will be called 
hundreds of times by all clients connected to DB?

Moreover, I've run absolutely same SQL statement as a PREPARED statement 
and as a Stored procedure returning SET OF CUSTOM TYPE. It contained 
several union queries over a database of 6 millions of records returning 
a recordset of 1.5 millions of records. It took 5 min. for the prepared 
statement to return the results vs. 16 minutes that was required by SP. 
Memory consumption in case of prepared statement was around 300 MB while 
it took over 800MB for SP.

It could be that there is a more efficient way to return recordsets from 
SP's that I do not know, but I couldn't find it in Postgre documentation.

Besides, table definitions tend to change during time. How often did you 
add columns to a table? In this case custom data types must be upgraded, 
as well as EVERY stored procedure using that type. In case of prepared 
statements, you can upgrade only those you need to. This is extremely 
useful for building and improving reports.

[*** not important, just a presentation of something we found useful in 
other engines ***]

There is an interesting concept in JET engine (with all of deficiency of 
the engine itself); it allows building PREPARED statements over other 
PREPARED statements automatically passing parameters by name to the 
underlying PREPARED statement. This concept allows for realization of a 
base SQL statement preparing data for profit&loss report, and then using 
it in another SQL statement by adding joins to some specific tables 
(sectors and employees for instance). That way within minutes you can 
produce a profit&loss by sectors, or by employees or whatever.

What is the magic part, if we introduce new type of documents to our 
program that do influence profit&loss then we simply change the BASE 
prepared statement. And ALL reports based on it get "upgraded" 
automatically.

Best regards,
Milan Oparnica



Re: PERSISTANT PREPARE (another point of view)

From
Milan Oparnica
Date:
Tom Lane wrote:

> Most people around this project think that the best way to do that is to
> push as much logic as you can into server-side stored procedures.  That
> gives you every advantage that a persistent-prepared-statement feature
> would offer, and more besides:
> 

It's simply to complicated to return recordsets through server-side 
stored procedures. They are obviously designed to do complex data 
manipulation, returning few output variables informing the caller about 
final results. Returning records through sets of user-defined-types is 
memory and performance waste (please see my previous post as reply to 
Steve for more details). Plus it's hard to maintain and make 
improvements to such a system. I hate to see 800 user types made for 
every query we made as stored procedure.

I don't say it couldn't be done through sp but maybe you guys could 
provide us with much easier (and efficient) way to organize and fetch 
common SQL statements. Something between VIEWS and STORED PROCEDURES, 
something like PARAMETERIZED VIEWS or PERSISTENT PREPARED statement.

Either way, it would be a place where we could use only PURE SQL syntax.
I think it's 90% of what any database application does.
> * you can push procedural logic, as well as SQL, out of the application

Application developing tools usually offer bigger set of functions, 
objects, methods etc. than any DB stored procedure language can. There 
is also debugging, code version control software, team development 
software and lots of other stuff. It's just more efficient to keep the 
logic in the application part of the system. Just compare the IDE 
editors to any DB Admin Tool.

>> * you can improve performance by reducing the number of network round> trips needed to accomplish a
multi-SQL-statementtask>>             regards, tom lane>
 

I couldn't agree more. Such tasks are decidedly for SP's. I'm thinking 
about 90% of simple to mid-simple tasks (reports, logins, retriving 
customer and item properties, warehouse inventory and other stuff) that 
are simple matter of SQL or SQL's in a union with few parameters for 
filtering the data.

I see programmers hard-coding such SQL statements in PHP, C++, Delphi or 
VB projects. Why?  Is it to complex to have it implemented in Postgre 
engine? We have PREPARE statement, locally for the user. Is it possible 
to take it globally, for all users, and not to forget it when all 
connections dye?

It is a way to get all of SQL statement out of the application not only 
"as much logic as you can". As a leader of our development team I find 
it HIGHLY (and I mean HIGHLY) DESIRABLE.

Best regards,
Milan Oparnica


Re: PERSISTANT PREPARE (another point of view)

From
Milan Oparnica
Date:
Milan Oparnica wrote:
> 
> It's simply to complicated to return recordsets through server-side 
> stored procedures. They are obviously designed to do complex data 
> manipulation, returning few output variables informing the caller about 
> final results. Returning records through sets of user-defined-types is 
> memory and performance waste (please see my previous post as reply to 
> Steve for more details). Plus it's hard to maintain and make 
> improvements to such a system. I hate to see 800 user types made for 
> every query we made as stored procedure.

Is this topic completely out of scope in Postgre ?
If I'm missing something too obvious or too important, please let me 
know what.

I run over and over through internet and Postgre documentation and still 
found nothing.

Is there a better place to communicate with Postgre developers ?

Sincerely,

Milan Oparnica


Re: PERSISTANT PREPARE (another point of view)

From
"Pavel Stehule"
Date:
Hello

2008/7/16 Milan Oparnica <milan.opa@gmail.com>:
> Milan Oparnica wrote:
>>
>> It's simply to complicated to return recordsets through server-side stored
>> procedures. They are obviously designed to do complex data manipulation,
>> returning few output variables informing the caller about final results.
>> Returning records through sets of user-defined-types is memory and
>> performance waste (please see my previous post as reply to Steve for more
>> details). Plus it's hard to maintain and make improvements to such a system.
>> I hate to see 800 user types made for every query we made as stored
>> procedure.
>
> Is this topic completely out of scope in Postgre ?
> If I'm missing something too obvious or too important, please let me know
> what.
>
> I run over and over through internet and Postgre documentation and still
> found nothing.
>

try to write prototype and show advantages. I am able to undestand
advantages of persistent prep. stamenents, but I see some disadvatage
too. Mainly you have to manage some shared memory space for stored
plans. It's not easy task - MySQL develepoers can talk. Implemenation
on postgresql is little bit dificult - lot of structures that lives in
processed memory have to be moved to shared memory.

This feature is nice, but question is - who do write it? Actually this
problem is solved from outside - with pooling.

Regards
Pavel Stehule

> Is there a better place to communicate with Postgre developers ?
>
> Sincerely,
>
> Milan Oparnica
>
> --
> Sent via pgsql-sql mailing list (pgsql-sql@postgresql.org)
> To make changes to your subscription:
> http://www.postgresql.org/mailpref/pgsql-sql
>


Re: PERSISTANT PREPARE (another point of view)

From
Richard Huxton
Date:
Milan Oparnica wrote:
> Milan Oparnica wrote:
>>
>> It's simply to complicated to return recordsets through server-side 
>> stored procedures. They are obviously designed to do complex data 
>> manipulation, returning few output variables informing the caller 
>> about final results. Returning records through sets of 
>> user-defined-types is memory and performance waste (please see my 
>> previous post as reply to Steve for more details).

I'm not convinced it's always a win one way or another.
>> Plus it's hard to
>> maintain and make improvements to such a system. I hate to see 800 
>> user types made for every query we made as stored procedure.
> 
> Is this topic completely out of scope in Postgre ?
> If I'm missing something too obvious or too important, please let me 
> know what.

You still haven't said what's "too complicated" about defining a function:

CREATE FUNCTION users_at_dotcom(text) RETURNS SETOF users AS $$  SELECT * FROM users WHERE email LIKE '%@' || $1 ||
'.com';
$$ LANGUAGE SQL;

SELECT * FROM users_at_dotcom('archonet'); uid |  uname  |         email
-----+---------+-----------------------   1 | richard | richardh@archonet.com


--   Richard Huxton  Archonet Ltd


Re: PERSISTANT PREPARE (another point of view)

From
Milan Oparnica
Date:
Pavel wrote:

> 
> try to write prototype and show advantages... 

Prototype of what, implementation into Postgre or just efficiency of 
PRESISTANT PREPARE idea ?

> ...but I see some disadvatage
> too. Mainly you have to manage some shared memory space for stored
> plans. It's not easy task - MySQL develepoers can talk. Implemenation
> on postgresql is little bit dificult - lot of structures that lives in
> processed memory have to be moved to shared memory.
> 

Is it solved in MySQL or they've just tried ?

We could have only PREP STATEMENT definition stored in shared memory 
(probably something like stored procedures), and it could be run in 
local processed memory. We could even assume only fetching data would be 
used through PREP STATEMENTS for start, and later introduce data 
modification. Is there some simplified PG algorithm we could use to 
understand the amount of work needed for introducing such feature to PG?

> This feature is nice, but question is - who do write it? 

With a little help form PG developers and good documentation perhaps I 
could put some programmers from my team on this job. They are mostly C++ 
programmers but we have Delphi and Java if needed.

> Actually this problem is solved from outside - with pooling.
> 

I'm very interested to learn more about this solution. Can you please 
send me details or some links where I could research this solution ?


Thank you for your reply Pavel.


Re: PERSISTANT PREPARE (another point of view)

From
Milan Oparnica
Date:
Richard Huxton wrote:
>>    Milan Oparnica wrote:>>>>        It's simply to complicated to return recordsets through >>server-side stored
procedures.They are obviously designed to do >>complex data manipulation ...
 
> Richard wrote:>I'm not convinced it's always a win one way or another.>You still haven't said what's "too
complicated"about defining a >function:>>CREATE FUNCTION users_at_dotcom(text) RETURNS SETOF users AS $$>  SELECT *
FROMusers WHERE email LIKE '%@' || $1 || '.com';>$$ LANGUAGE SQL;>  Richard Huxton>  Archonet Ltd
 
-------------------------------------------------------------------
Hi Richard,

It sounds like you suggest not using PREPARED statement nor stored 
procedures to fetch data. What do you think is the best way ?

The example you posted is the only situation where it's simple to use 
stored procedures to fetch data.

--------------------------------------------------------------------
Try to write following simple scenario:

a. Data is retrieved from two tables in INNER JOIN
b. I don't need all fields, but just some of them from both tables

Lets call tables Customers and Orders.

Definition of tables are:
Customers (CustomID INTEGER, Name TEXT(50), Adress TEXT(100))
Orders (OrderID INTEGER, CustomID INTEGER, OrderNum TEXT(10))

Now I need a list of order numbers for some customer:

SELECT C.CustomID, C.Name, O.OrderNum
FROM Customers C INNER JOIN Orders  O ON C.CustomID=O.CustomID
WHERE C.Name LIKE <some input parameter>

Can you write this without defining an SETOF custom data type ?
----------------------------------------------------------------------
NOTE! THIS IS VERY SIMPLIFIED REPRESENTATION OF REAL-LIFE STRATEGY.
----------------------------------------------------------------------
We sometimes have JOINS up to 10 tables.

Besides, using report engines (like Crystal Reports) forces you to avoid 
queries where column order of the recordset can change. If you built a 
report on a query having CutomID,Name,OrderNum columns adding a column 
(CustomID,Name,Adress,OrderNum) will require recompiling the report if 
you want it to give correct results.

Thats one of the reasons we avoid SELECT * statements. Another is 
because some user roles do not have permissions to examine table 
structures. In such cases SELECT * returns error.

I hope I managed to present what I meant by "too complicated" when using 
stored procedures to fetch data.

PREPARED statements do not suffer from such overhead. They simply return 
records as if the statement was prepared in the client.

I will repeat, it took 5 minutes for prepared statement to return 
results of the same SQL that took 16 minutes for the stored procedure to 
do so. SP was written to return SETOF user type. If you want, I'll send 
you the exact SQL and the database. Later we tested other queries and it 
was always better performance using prepared statements then stored 
procedures with SETOF user defined types.

Best regards,

Milan Oparnica


Re: PERSISTANT PREPARE (another point of view)

From
Milan Oparnica
Date:
Richard Huxton wrote:
>>    Milan Oparnica wrote:>>>>        It's simply to complicated to return recordsets through >>server-side stored
procedures.They are obviously designed to do >>complex data manipulation ...
 
> Richard wrote:>I'm not convinced it's always a win one way or another.>You still haven't said what's "too
complicated"about defining a >function:>>CREATE FUNCTION users_at_dotcom(text) RETURNS SETOF users AS $$>  SELECT *
FROMusers WHERE email LIKE '%@' || $1 || '.com';>$$ LANGUAGE SQL;>  Richard Huxton>  Archonet Ltd
 
-------------------------------------------------------------------
Hi Richard,

It sounds like you suggest not using PREPARED statement nor stored 
procedures to fetch data. What do you think is the best way ?

The example you posted is the only situation where it's simple to use 
stored procedures to fetch data.

--------------------------------------------------------------------
Try to write following simple scenario:

a. Data is retrieved from two tables in INNER JOIN
b. I don't need all fields, but just some of them from both tables

Lets call tables Customers and Orders.

Definition of tables are:
Customers (CustomID INTEGER, Name TEXT(50), Adress TEXT(100))
Orders (OrderID INTEGER, CustomID INTEGER, OrderNum TEXT(10))

Now I need a list of order numbers for some customer:

SELECT C.CustomID, C.Name, O.OrderNum
FROM Customers C INNER JOIN Orders  O ON C.CustomID=O.CustomID
WHERE C.Name LIKE <some input parameter>

Can you write this without defining an SETOF custom data type ?
----------------------------------------------------------------------
NOTE! THIS IS VERY SIMPLIFIED REPRESENTATION OF REAL-LIFE STRATEGY.
----------------------------------------------------------------------
We sometimes have JOINS up to 10 tables.

Besides, using report engines (like Crystal Reports) forces you to avoid 
queries where column order of the recordset can change. If you built a 
report on a query having CutomID,Name,OrderNum columns adding a column 
(CustomID,Name,Adress,OrderNum) will require recompiling the report if 
you want it to give correct results.

Thats one of the reasons we avoid SELECT * statements. Another is 
because some user roles do not have permissions to examine table 
structures. In such cases SELECT * returns error.

I hope I managed to present what I meant by "too complicated" when using 
stored procedures to fetch data.

PREPARED statements do not suffer from such overhead. They simply return 
records as if the statement was prepared in the client.

I will repeat, it took 5 minutes for prepared statement to return 
results of the same SQL that took 16 minutes for the stored procedure to 
do so. SP was written to return SETOF user type. If you want, I'll send 
you the exact SQL and the database. Later we tested other queries and it 
was always better performance using prepared statements then stored 
procedures with SETOF user defined types.

Best regards,

Milan Oparnica


Re: PERSISTANT PREPARE (another point of view)

From
Milan Oparnica
Date:
I found this link from IBM DB2 developers showing why PERSISTENT PREPARE 
is a good idea and how could it be implemented.

http://www.hoadb2ug.org/Docs/Favero20606.pdf

It seems that main benefit (beside efficiency) is memory.
Having number of connections all with dozens of PREPARED statements 
consumes lot of memory.

If we put these statements in global space (perhaps not even in RAM 
memory until needed) we could reuse optimization plans as well as 
physical space needed to store them.

I also found articles:

http://archives.postgresql.org/pgsql-hackers/2008-04/msg00867.php

and

http://archives.postgresql.org/pgsql-performance/2008-03/msg00480.php

all about users trying to explain PERSISTENT PREPARE (some refer to it 
as global prepare).


There are also some guys who actually made some code for PERSISTENT PREPARE:

http://archives.postgresql.org/pgsql-hackers/2008-03/msg01228.php
and
http://archives.postgresql.org/pgsql-hackers/2008-03/msg01219.php


PEOPLE NEED THIS FEATURE !!! It is not discovering the wheel but it will 
simplify DB programming and even gain some performance.

NONE OF POPULAR SQL DBMS (Oracle, MS SQL, MySQL, Postgre, INTERBASE, 
FIREBIRD) HAVE THIS FEATURE.

WHY ?


Re: PERSISTANT PREPARE (another point of view)

From
Craig Ringer
Date:
Milan Oparnica wrote:
> I found this link from IBM DB2 developers showing why PERSISTENT PREPARE 
> is a good idea and how could it be implemented.

[snip]

> NONE OF POPULAR SQL DBMS (Oracle, MS SQL, MySQL, Postgre, INTERBASE, 
> FIREBIRD) HAVE THIS FEATURE.
> 
> WHY ?

I suspect that people tend to use SQL or PL/PgSQL stored procedures 
instead. I'm not 100% sure SQL functions cache their query plans, but I 
know PL/PgSQL does.

Exactly what is gained by the use of persistent prepare over the use of 
a stored procedure?

What would the interface to the feature be through database access 
drivers like JDBC? Explicit PREPARE GLOBAL or similar, then invocation 
with EXECUTE ?

How would users using increasingly common layers like Hibernate/JPA use it?

I'm also curious about how you'd address the possible need for periodic 
re-planning as the data changes, though AFAIK SQL functions suffer from 
the same limitation there.

I guess I personally just don't understand what the point of the 
persistent prepare feature you describe is. However, this post that you 
linked to:

http://archives.postgresql.org/pgsql-hackers/2008-04/msg00867.php

actually describes a query plan cache, rather than persistent prepare. 
The post assumes the app will explicitly manage the cache, which I'm not 
sure is a good idea, but I can see the point of a plan cache. There 
might be some heuristics Pg could use to decide what to cache and to 
evict (planner time cost vs memory use, frequency of use, etc) so the 
app doesn't have to know or care about the plan cache.  However, I'm not 
too sure how you'd match an incoming query to a cached plan, and 
determine that the plan was still valid, with enough speed to really 
benefit from the plan cache. Then again, I don't know much about Pg's 
innards, so that doesn't mean much.

Tom Lane responded to that post to point out some of the complexities:

http://archives.postgresql.org/pgsql-hackers/2008-04/msg00868.php

--
Craig Ringer


Re: PERSISTANT PREPARE (another point of view)

From
Craig Ringer
Date:
Earlier, I wrote:

> Exactly what is gained by the use of persistent prepare over the use of 
> a stored procedure?

Er, ENOCOFFEE. Sorry.

The benefit is obvious with use of global prepared statements at the 
wire protocol level rather than via SQL EXECUTE . It's a lot more 
efficient than EXECUTE or SELECT function(params).

It's pretty clear that there are some tricky aspects though, what with 
schema search paths, role priveleges, etc.

--
Craig Ringer


Re: PERSISTANT PREPARE (another point of view)

From
"Pavel Stehule"
Date:
2008/7/20 Milan Oparnica <milan.opa@gmail.com>:
> Pavel wrote:
>
>>
>> try to write prototype and show advantages...
>
> Prototype of what, implementation into Postgre or just efficiency of
> PRESISTANT PREPARE idea ?

really prototype


>
>> ...but I see some disadvatage
>> too. Mainly you have to manage some shared memory space for stored
>> plans. It's not easy task - MySQL develepoers can talk. Implemenation
>> on postgresql is little bit dificult - lot of structures that lives in
>> processed memory have to be moved to shared memory.
>>
>
> Is it solved in MySQL or they've just tried ?

http://www.mysqlperformanceblog.com/2006/08/02/mysql-prepared-statements/

Do not forget to close prepared statements - Many memory leaks
reported in MySQL Server turned out to be prepare statements or
cursors which were forgotten to be closed. Watch Com_stmt_prepare and
Com_stmt_close to see if you're closing all prepared statements. In
newer versions you can also use prepared_stmt_count variable to track
number of open statements diretly. You can also adjust
max_prepared_stmt_count variable which limits how many statements can
be open at the same time to avoid overload.

>
> We could have only PREP STATEMENT definition stored in shared memory
> (probably something like stored procedures), and it could be run in local
> processed memory. We could even assume only fetching data would be used
> through PREP STATEMENTS for start, and later introduce data modification. Is
> there some simplified PG algorithm we could use to understand the amount of
> work needed for introducing such feature to PG?


there is some complications with portability - shared memory is slow
on windows :( but probably  there isn't problem save plan into shared
memory. Main difficulties is memory maintaining.
>
>> This feature is nice, but question is - who do write it?
>
> With a little help form PG developers and good documentation perhaps I could
> put some programmers from my team on this job. They are mostly C++
> programmers but we have Delphi and Java if needed.

PostgreSQL is solo C code
http://wiki.postgresql.org/wiki/Development_information

>
>> Actually this problem is solved from outside - with pooling.
>>
>
> I'm very interested to learn more about this solution. Can you please send
> me details or some links where I could research this solution ?

pgpool??

>
>
> Thank you for your reply Pavel.

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


Re: PERSISTANT PREPARE (another point of view)

From
"Scott Marlowe"
Date:
On Tue, Jul 22, 2008 at 12:43 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:
> 2008/7/20 Milan Oparnica <milan.opa@gmail.com>:
>> Is it solved in MySQL or they've just tried ?
>
> http://www.mysqlperformanceblog.com/2006/08/02/mysql-prepared-statements/

Wow, the discussion at the bottom of that page made me really think.
In MySQL you rely on the statement cache to provide data really fast
without worrying too much about transactional semantics.  In
PostgreSQL you set up a set of 1 or more slony machines to act as
cache / increase parallel performance.  Or just throw more CPU and
memory at it along with memcached.  Or both.


Re: PERSISTANT PREPARE (another point of view)

From
Jeff Williams
Date:
On 20/07/08 22:16, Milan Oparnica wrote:
> Try to write following simple scenario:
>
> a. Data is retrieved from two tables in INNER JOIN
> b. I don't need all fields, but just some of them from both tables
>
> Lets call tables Customers and Orders.
>
> Definition of tables are:
> Customers (CustomID INTEGER, Name TEXT(50), Adress TEXT(100))
> Orders (OrderID INTEGER, CustomID INTEGER, OrderNum TEXT(10))
>
> Now I need a list of order numbers for some customer:
>
> SELECT C.CustomID, C.Name, O.OrderNum
> FROM Customers C INNER JOIN Orders  O ON C.CustomID=O.CustomID
> WHERE C.Name LIKE <some input parameter>
>
You can do this with cursors, but I'm not sure if you still get the
query caching?

CREATE FUNCTION test(refcursor, input varchar) RETURNS refcursor AS $$
BEGIN   OPEN $1 FOR SELECT C.CustomID, C.Name, O.OrderNum        FROM Customers C INNER JOIN Orders  O ON
C.CustomID=O.CustomID       WHERE C.Name LIKE '%' || input || '%';   RETURN $1;
 
END
$$ LANGUAGE plpgsql;

Then to use:

BEGIN;
SELECT test('curs', <some input parameter>);
FETCH ALL FROM curs;
END;

Jeff


Re: PERSISTANT PREPARE (another point of view)

From
Milan Oparnica
Date:
Craig Ringer wrote:
> Milan Oparnica wrote:
>> I found this link from IBM DB2 developers showing why PERSISTENT 
>> PREPARE is a good idea and how could it be implemented.
> 
> [snip]
> 
>> NONE OF POPULAR SQL DBMS (Oracle, MS SQL, MySQL, Postgre, INTERBASE, 
>> FIREBIRD) HAVE THIS FEATURE.
>>
>> WHY ?
> 
> I suspect that people tend to use SQL or PL/PgSQL stored procedures 
> instead. I'm not 100% sure SQL functions cache their query plans, but I 
> know PL/PgSQL does.
> 
> Exactly what is gained by the use of persistent prepare over the use of 
> a stored procedure?
> 

Its easier to write and call prepared statements then SP's.
When writing, you just create parameters and SQL body of the statement.
When calling from the application or report engine, all you have to do 
is "EXEC <statement name> (<parameters>)".

In case of SP's written as SET OF CustomDataType it's pretty easy to 
call ("SELECT * FROM <proc> (<params>)) but its hard to maintain 
CutomDataType when changing table structures.

In case of SP's written using CURSORS calling convention is not simple.

BEGIN;
SELECT <proc>('cursor_name', <input parameter>);
FETCH ALL FROM cursor_name;
END;

This usually requires using more complicating ways to define source 
recordsets in reports designers. I'm also not sure how cursors use 
indexes of the tables. I've run some tests on several millions records 
with and without indexes and found out that there was no significant 
difference in performance. Plus, for now, CURSORS remain READ-ONLY in PG.

There is one thing more. Prepared statements could be used as table-type  (or view-type) datasource. That means we
couldrun prepared statements 
 
over other prepared statements accepting same parameters. This makes 
possible creating complex "low-level" BASE queries and dozens of 
reporting queries that rely on them. Something like subquery structures:

SELECT A.Fld1,B.Fld2
FROM
(SELECT Fld1 FROM Table1 WHERE xxx) A INNER JOIN Table2 B ON A.Fld1=B.Fld2
WHERE yyy



> What would the interface to the feature be through database access 
> drivers like JDBC? Explicit PREPARE GLOBAL or similar, then invocation 
> with EXECUTE ?
> 

They could remain the same. If possible, when calling EXECUTE <xxx> PG 
could try local-then global (or reverse) PREPARED STATEMENTS pool, and 
run the statement that was first found. This is greatly simplified. It 
would require much detailed planning if this option is to be built in PG.

> How would users using increasingly common layers like Hibernate/JPA use it?
> 

I don't now, I never used Hibernate/JPA. Somebody could speak for that. 
Making PERSISTANT PREPARE statement available in PG doesn't mean that 
everybody must use it.

> I'm also curious about how you'd address the possible need for periodic 
> re-planning as the data changes, though AFAIK SQL functions suffer from 
> the same limitation there.
> 

Perhaps there could be several ways. It could be implemented within 
VACUUM procedure. It could re-plan all global prepared statements 
according to new circumstances. There should also be a manual 
re-planning command of specific statement maybe even with passing 
parameters to it so the optimization could be even more efficient.

> I guess I personally just don't understand what the point of the 
> persistent prepare feature you describe is. However, this post that you 
> linked to:
> 
> http://archives.postgresql.org/pgsql-hackers/2008-04/msg00867.php
> 
> actually describes a query plan cache, rather than persistent prepare. 
> The post assumes the app will explicitly manage the cache, which I'm not 
> sure is a good idea, but I can see the point of a plan cache. There 
> might be some heuristics Pg could use to decide what to cache and to 
> evict (planner time cost vs memory use, frequency of use, etc) so the 
> app doesn't have to know or care about the plan cache.  However, I'm not 
> too sure how you'd match an incoming query to a cached plan, and 
> determine that the plan was still valid, with enough speed to really 
> benefit from the plan cache. Then again, I don't know much about Pg's 
> innards, so that doesn't mean much.
> 
> Tom Lane responded to that post to point out some of the complexities:
> 
> http://archives.postgresql.org/pgsql-hackers/2008-04/msg00868.php
> 
> -- 
> Craig Ringer
> 

I think persistent prepare has to do something with global caching 
plans. Preparing statement actually prepares a plan of its execution 
giving us the possibility to execute it. With persistent prepare 
statement it somehow these plans have to go from local to global. I 
agree they shouldn't be managed by app itself. App can only create 
requests for creation, modification, execution and removing of such object.

This post is about a point of view. I know we can use stored procedures 
and views and other good features of PG to manipulate all data we need.

What I aim is: it can be done in more simple and efficient way with 
PERSISTENT PREPARE implementation. Let me point the key benefits:

- huge number of database developers could use this technique without 
getting involved with CURSORS and CUSTOM DATA TYPE SETS.

This means a lot of hard-coded sQL commands built into apps itself 
easily transfered to database layer.

It also means thousands of Microsoft Jet based applications migrated to 
PG. Why ? Because databases are getting larger as project advance and 
companies grow, and PG could offer an easier way to upsize then their 
own Microsoft SQL engine does.

It also means a lot of new and less experienced database programmers 
turn their focus on PG. Its much easier to understand PREPARED 
statements than SP constructions returning rowsets.


- EXEC(UTE) is a well known SQL command understood and implemented by 
any database engine almost the same way. It's also natively supported by 
report designing tools and ADO and ODBC drivers. It means that front end 
app doesn't even have to notice if the statement is locally or globally 
prepared.

This means that some modules of the system could create global 
statements and other modules would simply use them, assuming that they 
are in the DB as a part of "setup" process.


Lots of functionality is implemented in PG not all of them used by 
developers. My opinion is that implementation of PERSISTENT or GLOBAL 
PREPARED STATEMENT would be of much use.


Re: PERSISTANT PREPARE (another point of view)

From
Milan Oparnica
Date:
Jeff Williams wrote:

> You can do this with cursors, but I'm not sure if you still get the
> query caching?
> 

I can do it with cursors, I don't get query cache but that is for now 
not an issue.

Issue is performance.

Although using cursors show better performance over using SET OF user 
defined data types, it still swallows huge amount of memory.

Here are the results of a query (I post the query at the end just for 
sake of complexity example) running on database of 1.6 GB of data and 
around 5 million of records:
        Time    Approx RAM usage    Swaping
PREPARE Statement    5 min.    300 MB            None
SP with SET OF        16 min.    800 MB            Heavy
SP with cursor        9 min.    800 MB            Medium

Environment:

Run on Query Tool of pgAdmin III. It does no data modification.
Number of clients: 1
PostgreSQL version 8.3
Processor P4 2.66 GHZ
RAM memory  1 GB.

There where no other active programs or demanding services running in 
the background.


I presume adding more RAM would increase performance but we usually have 
10 to 20 clients working at a time. I guess that would put some load.

Besides, fetching records from cursor type SP requires transactional 
approach in calling convention (BEGIN....statment...END). At this moment 
I don't know if this can be done in our main report designer tool - 
Business Objects (former Crystal Reports).

Best regards,

Milan Oparnica


Here is the text of SQL statement:

Note: All fields in join are indexed and every where field is also 
indexed except boolean fields.

CREATE FUNCTION aaTestCurs (refcursor, insklid integer, indatdo 
timestamp without time zone) RETURNS refcursor AS $$
BEGIN    OPEN $1 FOR    SELECT 10 AS 
Poredak,U.UlID,U.DatDoc,DT.FKomis,DT.FSCObrac,DT.FNivelTot,DT.FNivelParc,
U.DocTip,SU.SasUlID,SU.ElID,ROUND(CAST(SU.KolAS NUMERIC),8) AS 
 
Kol,SU.NCena,ROUND(CAST(SU.TKol AS NUMERIC),8) AS TKol,      SU.SCena,SU.SklID,0 AS Obradjen,0 AS IzmSC,0 AS ImaIzmena,
    U.Link,SU.FCena,SU.Popust,SU.Marza,SU.MCena,SU.MPorez,SU.KKol,
SU.PorezU,SUN.NNKol,SUN.NPCena,SUN.NTotal,SUN.NTotPP,SUN.NTotPU,0
 
AS NivelEdited,      SUN.NNKol AS NivelOldKol,0 AS LastTKol,0 AS LastSCena,SK.RacTipSKL,      U.DTStamp AS
Tabela,U.DopSklID,DT.FPrenos,SK.FRemote     FROM(((defDocTip AS DT INNER JOIN Ulaz AS U ON DT.DTID = 
 
U.DocTip) INNER JOIN SasUlaz AS SU ON U.UlID = SU.UlID) INNER JOIN 
Skladista AS SK ON U.SklID = SK.SklID) LEFT JOIN SasUlazNivel AS SUN ON 
SU.SasUlID = SUN.SasUlID      WHERE DT.FSCObrac AND NOT(SK.FSkipSCObr <> false) AND 
NOT(SK.FSkipNivel <> false) AND U.DatDoc <= InDatDo      UNION ALL      SELECT 20 AS 
Poredak,U.UlID,U.DatDoc,DT.FKomis,DT.FSCObrac,DT.FNivelTot,DT.FNivelParc,
U.DocTip,SU.SasUlID,SU.ElID,ROUND(CAST(SU.KolAS 
 
NUMERIC),8),SU.NCena,ROUND(CAST(SU.TKol AS NUMERIC),8),      SU.SCena,SU.SklID,0 AS Obradjen,0 AS IzmSC,0 AS
ImaIzmena,U.Link,
SU.FCena,SU.Popust,SU.Marza,SU.MCena,SU.MPorez,SU.KKol,SU.PorezU,SUN.NNKol,
SUN.NPCena,SUN.NTotal,SUN.NTotPP,SUN.NTotPU,0AS NivelEdited,      SUN.NNKol AS NivelOldKol,0 AS LastTKol,0 AS 
 
LastSCena,SK.RacTipSKL,(U.DTStamp -(200000*case when DT.Rank > 50000 
then -1 else 0
end)) AS Tabela,      U.DopSklID,DT.FPrenos,SK.FRemote      FROM(((defDocTip AS DT INNER JOIN Ulaz AS U ON   DT.DTID =

U.DocTip) INNER JOIN SasUlaz AS SU ON U.UlID = SU.UlID) INNER JOIN 
Skladista AS SK ON U.SklID = SK.SklID)  LEFT JOIN SasUlazNivel AS SUN ON 
SU.SasUlID = SUN.SasUlID      WHERE NOT DT.FSCObrac AND NOT(SK.FSkipSCObr <> false) AND 
NOT(SK.FSkipNivel <> false) AND U.DocTip <> 31 AND U.DatDoc <= InDatDo      UNION ALL      SELECT 28 AS
Poredak,U.UlID,U.DatDoc,FalseAS 
 
FKomis,DT.FSCObrac,DT.FNivelTot,      DT.FNivelParc,U.DocTip,SU.SasUlID,SU.ElID,ROUND(CAST(SU.Kol AS 
NUMERIC),8),SU.NCena,ROUND(CAST(SU.TKol AS NUMERIC),8),      SU.SCena,SU.SklID,0 AS Obradjen,0 AS IzmSC,0 AS
ImaIzmena,
U.Link,SU.FCena,SU.Popust,SU.Marza,SU.MCena,SU.MPorez,SU.KKol,SU.PorezU,
SUN.NNKol,SU.RCena,SUN.NTotal,SUN.NTotPP,SUN.NTotPU,0AS 
 
NivelEdited,      SUN.NNKol AS NivelOldKol,0 AS LastTKol,0 AS LastSCena,SK.RacTipSKL,      U.DTStamp AS
Tabela,U.DopSklID,DT.FPrenos,SK.FRemote     FROM(((defDocTip AS DT INNER JOIN Ulaz AS U ON DT.DTID = 
 
U.DocTip) INNER JOIN SasUlaz AS SU ON U.UlID = SU.UlID) INNER JOIN 
Skladista AS SK ON U.SklID = SK.SklID)  LEFT JOIN SasUlazNivel AS SUN ON 
SU.SasUlID = SUN.SasUlID      WHERE U.DatDoc <= InDatDo AND NOT(SK.FSkipSCObr <> false) AND 
NOT(SK.FSkipNivel <> false) AND U.DocTip = 31 AND((SK.RacTipSKL = 3 
AND(DT.FMP <> false)) OR(SK.RacTipSKL <> 3 AND(DT.FVP <> false)))      UNION ALL SELECT 30 AS Poredak,0 AS
UlID,O.DatDoc,FalseAS 
 
FKomis,False,False,False,2 AS DocTip,      0 AS SasUlID,SO.ElID,-SUM(SO.Kol) AS Kol,0 AS NCena,0 AS TKol,      0 AS
SCena,SK.SklID,0AS Obradjen,0 AS IzmSC,0 AS ImaIzmena,0 AS 
 
Link,      0 AS FCena,0 AS Popust,0 AS Marza,0 AS MCena,0 AS MPorez,0 AS 
KKol,0 AS PorezU,      0 AS NNKol,0 AS NPCena,0 AS NTotal,0 AS NTotPP,0 AS NTotPU,0 AS 
NivelEdited,      0 AS NivelOldKol,0 AS LastTKol,0 AS LastSCena,SK.RacTipSKL,      200000 AS Tabela,0 AS DopSklID,FALSE
ASFPrenos,      FALSE AS FRemote      FROM(Otpremnice AS O INNER JOIN SasOtp AS SO ON O.OtpID = 
 
SO.OtpID)  INNER JOIN Skladista AS SK ON SO.SklID = SK.SklID      WHERE O.DatDoc <= InDatDo AND SO.ElID < 1000000
GROUPBY O.DatDoc,SO.ElID,SK.SklID,SK.RacTipSKL      ORDER BY 3,Tabela,2;    RETURN $1;
 
END
$$ LANGUAGE plpgsql;


-- Executing query:
BEGIN;
SELECT aaTestCurs('curs', 1,'31.12.2008');
FETCH ALL FROM curs;
END;
Query result with 1 rows discarded.
Query result with 1564318 rows discarded.

Query returned successfully with no result in 531563 ms.

I guess I didn't populate the cursor.


Re: PERSISTANT PREPARE (another point of view)

From
"Pavel Stehule"
Date:
Hello

this is near my implemenation of stored procedures - it's not far from
your view on prepared statements. There  result of any unbound select
is directly forwarded to client - there is little bit different
syntax, but idea is same


create procedure foo(params)
as $$
begin select a, b, c from tab1 -- unbound select select ....
end;

and you can call with CALL statement. Curent implementation of SRF
function in plpgsql sn't eficient for big results - it needs
materialised table in memory. Pipeline Oracle's functions are better,
but we are limited one thread architecture.

regards
Pavel Stehule

2008/7/25 Milan Oparnica <milan.opa@gmail.com>:
> Jeff Williams wrote:
>
>> You can do this with cursors, but I'm not sure if you still get the
>> query caching?
>>
>
> I can do it with cursors, I don't get query cache but that is for now not an
> issue.
>
> Issue is performance.
>
> Although using cursors show better performance over using SET OF user
> defined data types, it still swallows huge amount of memory.
>
> Here are the results of a query (I post the query at the end just for sake
> of complexity example) running on database of 1.6 GB of data and around 5
> million of records:
>
>                        Time    Approx RAM usage        Swaping
> PREPARE Statement       5 min.  300 MB                  None
> SP with SET OF          16 min. 800 MB                  Heavy
> SP with cursor          9 min.  800 MB                  Medium
>
> Environment:
>
> Run on Query Tool of pgAdmin III. It does no data modification.
> Number of clients: 1
> PostgreSQL version 8.3
> Processor P4 2.66 GHZ
> RAM memory  1 GB.
>
> There where no other active programs or demanding services running in the
> background.
>
>
> I presume adding more RAM would increase performance but we usually have 10
> to 20 clients working at a time. I guess that would put some load.
>
> Besides, fetching records from cursor type SP requires transactional
> approach in calling convention (BEGIN....statment...END). At this moment I
> don't know if this can be done in our main report designer tool - Business
> Objects (former Crystal Reports).
>
> Best regards,
>
> Milan Oparnica
>
>
> Here is the text of SQL statement:
>
> Note: All fields in join are indexed and every where field is also indexed
> except boolean fields.
>
> CREATE FUNCTION aaTestCurs (refcursor, insklid integer, indatdo timestamp
> without time zone) RETURNS refcursor AS $$
> BEGIN
>    OPEN $1 FOR
>    SELECT 10 AS
> Poredak,U.UlID,U.DatDoc,DT.FKomis,DT.FSCObrac,DT.FNivelTot,DT.FNivelParc,
>      U.DocTip,SU.SasUlID,SU.ElID,ROUND(CAST(SU.Kol AS NUMERIC),8) AS
> Kol,SU.NCena,ROUND(CAST(SU.TKol AS NUMERIC),8) AS TKol,
>      SU.SCena,SU.SklID,0 AS Obradjen,0 AS IzmSC,0 AS ImaIzmena,
>      U.Link,SU.FCena,SU.Popust,SU.Marza,SU.MCena,SU.MPorez,SU.KKol,
>      SU.PorezU,SUN.NNKol,SUN.NPCena,SUN.NTotal,SUN.NTotPP,SUN.NTotPU,0 AS
> NivelEdited,
>      SUN.NNKol AS NivelOldKol,0 AS LastTKol,0 AS LastSCena,SK.RacTipSKL,
>      U.DTStamp AS Tabela,U.DopSklID,DT.FPrenos,SK.FRemote
>      FROM(((defDocTip AS DT INNER JOIN Ulaz AS U ON DT.DTID = U.DocTip)
> INNER JOIN SasUlaz AS SU ON U.UlID = SU.UlID) INNER JOIN Skladista AS SK ON
> U.SklID = SK.SklID) LEFT JOIN SasUlazNivel AS SUN ON SU.SasUlID =
> SUN.SasUlID
>      WHERE DT.FSCObrac AND NOT(SK.FSkipSCObr <> false) AND NOT(SK.FSkipNivel
> <> false) AND U.DatDoc <= InDatDo
>      UNION ALL
>      SELECT 20 AS
> Poredak,U.UlID,U.DatDoc,DT.FKomis,DT.FSCObrac,DT.FNivelTot,DT.FNivelParc,
>      U.DocTip,SU.SasUlID,SU.ElID,ROUND(CAST(SU.Kol AS
> NUMERIC),8),SU.NCena,ROUND(CAST(SU.TKol AS NUMERIC),8),
>      SU.SCena,SU.SklID,0 AS Obradjen,0 AS IzmSC,0 AS ImaIzmena,U.Link,
>
> SU.FCena,SU.Popust,SU.Marza,SU.MCena,SU.MPorez,SU.KKol,SU.PorezU,SUN.NNKol,
>      SUN.NPCena,SUN.NTotal,SUN.NTotPP,SUN.NTotPU,0 AS NivelEdited,
>      SUN.NNKol AS NivelOldKol,0 AS LastTKol,0 AS
> LastSCena,SK.RacTipSKL,(U.DTStamp -(200000*case when DT.Rank > 50000 then -1
> else 0
> end)) AS Tabela,
>      U.DopSklID,DT.FPrenos,SK.FRemote
>      FROM(((defDocTip AS DT INNER JOIN Ulaz AS U ON   DT.DTID = U.DocTip)
> INNER JOIN SasUlaz AS SU ON U.UlID = SU.UlID) INNER JOIN Skladista AS SK ON
> U.SklID = SK.SklID)  LEFT JOIN SasUlazNivel AS SUN ON SU.SasUlID =
> SUN.SasUlID
>      WHERE NOT DT.FSCObrac AND NOT(SK.FSkipSCObr <> false) AND
> NOT(SK.FSkipNivel <> false) AND U.DocTip <> 31 AND U.DatDoc <= InDatDo
>      UNION ALL
>      SELECT 28 AS Poredak,U.UlID,U.DatDoc,False AS
> FKomis,DT.FSCObrac,DT.FNivelTot,
>      DT.FNivelParc,U.DocTip,SU.SasUlID,SU.ElID,ROUND(CAST(SU.Kol AS
> NUMERIC),8),SU.NCena,ROUND(CAST(SU.TKol AS NUMERIC),8),
>      SU.SCena,SU.SklID,0 AS Obradjen,0 AS IzmSC,0 AS ImaIzmena,
>
> U.Link,SU.FCena,SU.Popust,SU.Marza,SU.MCena,SU.MPorez,SU.KKol,SU.PorezU,
>      SUN.NNKol,SU.RCena,SUN.NTotal,SUN.NTotPP,SUN.NTotPU,0 AS NivelEdited,
>      SUN.NNKol AS NivelOldKol,0 AS LastTKol,0 AS LastSCena,SK.RacTipSKL,
>      U.DTStamp AS Tabela,U.DopSklID,DT.FPrenos,SK.FRemote
>      FROM(((defDocTip AS DT INNER JOIN Ulaz AS U ON DT.DTID = U.DocTip)
> INNER JOIN SasUlaz AS SU ON U.UlID = SU.UlID) INNER JOIN Skladista AS SK ON
> U.SklID = SK.SklID)  LEFT JOIN SasUlazNivel AS SUN ON SU.SasUlID =
> SUN.SasUlID
>      WHERE U.DatDoc <= InDatDo AND NOT(SK.FSkipSCObr <> false) AND
> NOT(SK.FSkipNivel <> false) AND U.DocTip = 31 AND((SK.RacTipSKL = 3
> AND(DT.FMP <> false)) OR(SK.RacTipSKL <> 3 AND(DT.FVP <> false)))
>      UNION ALL SELECT 30 AS Poredak,0 AS UlID,O.DatDoc,False AS
> FKomis,False,False,False,2 AS DocTip,
>      0 AS SasUlID,SO.ElID,-SUM(SO.Kol) AS Kol,0 AS NCena,0 AS TKol,
>      0 AS SCena,SK.SklID,0 AS Obradjen,0 AS IzmSC,0 AS ImaIzmena,0 AS Link,
>      0 AS FCena,0 AS Popust,0 AS Marza,0 AS MCena,0 AS MPorez,0 AS KKol,0 AS
> PorezU,
>      0 AS NNKol,0 AS NPCena,0 AS NTotal,0 AS NTotPP,0 AS NTotPU,0 AS
> NivelEdited,
>      0 AS NivelOldKol,0 AS LastTKol,0 AS LastSCena,SK.RacTipSKL,
>      200000 AS Tabela,0 AS DopSklID,FALSE AS FPrenos,
>      FALSE AS FRemote
>      FROM(Otpremnice AS O INNER JOIN SasOtp AS SO ON O.OtpID = SO.OtpID)
>  INNER JOIN Skladista AS SK ON SO.SklID = SK.SklID
>      WHERE O.DatDoc <= InDatDo AND SO.ElID < 1000000
>      GROUP BY O.DatDoc,SO.ElID,SK.SklID,SK.RacTipSKL
>      ORDER BY 3,Tabela,2;
>    RETURN $1;
> END
> $$ LANGUAGE plpgsql;
>
>
> -- Executing query:
> BEGIN;
> SELECT aaTestCurs('curs', 1,'31.12.2008');
> FETCH ALL FROM curs;
> END;
> Query result with 1 rows discarded.
> Query result with 1564318 rows discarded.
>
> Query returned successfully with no result in 531563 ms.
>
> I guess I didn't populate the cursor.
>
> --
> Sent via pgsql-sql mailing list (pgsql-sql@postgresql.org)
> To make changes to your subscription:
> http://www.postgresql.org/mailpref/pgsql-sql
>


Re: PERSISTANT PREPARE (another point of view)

From
chester c young
Date:
1. like the idea because right now I'm having to track which prepared statement (sets) are in which session.  using
xcacheto track this, but little bit dangerous.  could query the database first but the whole idea is to take a load off
thedb.
 

2. perhaps "global" could mean simply that the definition is global - if called for session and not exist in session,
thensession prepares it first from the global def.  there would need to be a back reference in case the global def was
changedor dropped.
 

3. don't understand your statement about how prepared statements can be used as subqueries - you mean something like
 select .. from tab1 t1 where t1.col1 in( exec prep1(..) )

or exactly what?


     


Re: PERSISTANT PREPARE (another point of view)

From
Milan Oparnica
Date:
chester c young wrote:
> 1. like the idea because right now I'm having to track which prepared statement (sets) are in which session.  using
xcacheto track this, but little bit dangerous.  could query the database first but the whole idea is to take a load off
thedb.
 
> 

Thnx for support. The whole idea is to have DBMS support as much SQL 
related functionality as possible. This way you wouldn't have to wonder 
if the client has prepared the statement already or not. If you stored 
it in the public schema then it MUST be there.

> 2. perhaps "global" could mean simply that the definition is global - if called for session and not exist in session,
thensession prepares it first from the global def.  there would need to be a back reference in case the global def was
changedor dropped.
 
> 

Yes, this seems to be a good idea. Something like this would be easier 
to implement then having the whole process run in some shared memory 
space. The implementation could by like:

1. App cals SQL like "EXEC <statement_name>"
2. PG Engine looks first in local prepared statements as it does now
3. If it doesn't find it there it looks in public space
4. If it's found there copy both the SQL and the execution plan stored 
in global space to local process
5. Execute the statement as if it was prepared in local process.

Simplified greatly, new implementation could "only" add steps 3 and 4 to 
current implementation of PREPARED statements.

> 3. don't understand your statement about how prepared statements can be used as subqueries - you mean something like
> 
>   select .. from tab1 t1 where t1.col1 in( exec prep1(..) )
> 
> or exactly what?
> 

Well, its best explained on the example. Note that such construction 
would require extra coding from PG developers.

##1 Lets pretend we have a prepared statement:

PREPARE PS_Sector (InSector INTEGER) AS       SELECT SectorID,SectorName,SectorTypeFROM CompanySectorsWHERE SectorID =
InSector;


##2 Now we can build another statement over the firs one like this:

PREPARE PS_SectorExpences (InDateFrom DATETIME, InDateTo DATETIME, 
InSector INTEGER) ASSELECT S.SectorID,S.SectorName,S.SectorType,E.ExpType,E.AmmountFROM PS_Sector AS S INNER JOIN
CompanyExpencesAS EON S.SectorID=E.SectorIDWHERE E.Date>=InDateFrom AND E.Date<=InDateTo;
 


Let me explain. Statement ##2 uses PS_Sector in direct join with a table 
with expences. By automatically passing "by name" the parameter InSector 
to the underlaying prepared statement it first returns results from it. 
Then it joins it to the table CompanyExpences by field SectorID.

This may look complicated to implement but it's just a simplified 
version of implementing SUB-QUERIES. The same effect is gained if you 
simple replace the PS_Sector reference in ##2 by actual SQL statement it 
holds.

PREPARE PS_SectorExpences (InDateFrom DATETIME, InDateTo DATETIME, 
InSector INTEGER) ASSELECT S.SectorID,S.SectorName,S.SectorType,E.ExpType,E.AmmountFROM (SELECT
SectorID,SectorName,SectorTypeFROMCompanySectorsWHERE SectorID = InSector) AS S INNER JOIN CompanyExpences AS EON
S.SectorID=E.SectorIDWHEREE.Date>=InDateFrom AND E.Date<=InDateTo;
 


Only, this way, subquery can come with execution plan from ##1 prepared 
statemnt.


Where could this be used ?

Since it's obvious performance downgrade, you must have a good reason 
for using such approach. Mostly it's reporting !!!

Good report relies on data it gets. Sometimes statements needed for 
reporting purposes include very complex data selection. Usually it takes 
a long period of time until "everything is covered" by your SELECT 
query. At that point you can implement the core logic into a "base 
perpared statement" and then use prepared statements over it to get 
various aggregations, or different point of views of data.

But, the best thing is: WHEN YOU ADD SOMETHING TO BASIC LOGIC OF YOUR 
SYSTEM, YOU ONLY CHANGE THE BASE PREPARED STATEMENT. If you wrote it 
cleverly, than all statements built upon it WILL IMMEDIATELY SEE THE NEW 
IMPLEMENTATION. This is very powerful and efficient way of introducing 
improvements in the system not having to worry that majority of your 
reports will show false data until you find time to recompile them.

NOTE. You don't want to manipulate huge database systems this way but 
its very usable for 99% of small and medium business apps (databases up 
to few gigabytes). It greatly depends on your internal database 
representation though.

Best regards,

Milan Oparnica


Re: PERSISTANT PREPARE (another point of view)

From
Milan Oparnica
Date:
Pavel Stehule wrote:
> Hello
> 
> this is near my implemenation of stored procedures - it's not far from
> your view on prepared statements. There  result of any unbound select
> is directly forwarded to client - there is little bit different
> syntax, but idea is same
> 
> 
> create procedure foo(params)
> as $$
> begin
>   select a, b, c from tab1 -- unbound select
>   select ....
> end;
> 
> and you can call with CALL statement. Curent implementation of SRF
> function in plpgsql sn't eficient for big results - it needs
> materialised table in memory. Pipeline Oracle's functions are better,
> but we are limited one thread architecture.
> 
> regards
> Pavel Stehule
> 

Yeah, this would be pretty the same.

I just didn't understand if this is already implemented in PG ?

I've tried to create a PROCEDURE in QueryTool of pgAdminIII and I get 
following result:

ERROR:  syntax error at or near "PROCEDURE"
LINE 1: CREATE PROCEDURE aatestubnd(refcursor, insklid integer, inda...               ^

********** Error **********

ERROR: syntax error at or near "PROCEDURE"
SQL state: 42601
Character: 8


If I try with CREATE FUNCTION I get this result (as expected):

ERROR:  function result type must be specified

********** Error **********

ERROR: function result type must be specified
SQL state: 42P13


Is this because of QueryTool's limitations or is this feature not yet 
implemented in Postgre ?

Though, CREATE PROCEDURE should be a valid SQL 92 standard procedure.

Best regards,

Milan Oparnica


Re: PERSISTANT PREPARE (another point of view)

From
chester c young
Date:
> > 2. perhaps "global" could mean simply that
> the definition is global - if called for session and not
> exist in session, then session prepares it first from the
> global def.  there would need to be a back reference in
> case the global def was changed or dropped.
> > 
> 
> Yes, this seems to be a good idea. Something like this
> would be easier 
> to implement then having the whole process run in some
> shared memory 
> space. The implementation could by like:
> 
> 1. App cals SQL like "EXEC
> <statement_name>"
> 2. PG Engine looks first in local prepared statements as it
> does now
> 3. If it doesn't find it there it looks in public space
> 4. If it's found there copy both the SQL and the
> execution plan stored 
> in global space to local process
> 5. Execute the statement as if it was prepared in local
> process.
> 
> Simplified greatly, new implementation could
> "only" add steps 3 and 4 to 
> current implementation of PREPARED statements.

I think it only makes sense if the prepared statement is in the session.

For example, say the Globally submitted statement is  stmt: "select * from tab1"
assume  Session #1 has search_path=schema1  Session #2 has search_path=schema2
if session #1 attempts to exec stmt, it prepare and use schema1
if session #2 attempts to use stmt, if prepared globally, disaster

in submitted globally, it is not prepared at all until used, but, if ever used, prepared in the current session's
environment. really more like a rule who's preparation is remembered in the session.
 



     


Re: PERSISTANT PREPARE (another point of view)

From
"Pavel Stehule"
Date:
Hello

2008/7/28 Milan Oparnica <milan.opa@gmail.com>:
> Pavel Stehule wrote:
>>
>> Hello
>>
>> this is near my implemenation of stored procedures - it's not far from
>> your view on prepared statements. There  result of any unbound select
>> is directly forwarded to client - there is little bit different
>> syntax, but idea is same
>>
>>
>> create procedure foo(params)
>> as $$
>> begin
>>  select a, b, c from tab1 -- unbound select
>>  select ....
>> end;
>>
>> and you can call with CALL statement. Curent implementation of SRF
>> function in plpgsql sn't eficient for big results - it needs
>> materialised table in memory. Pipeline Oracle's functions are better,
>> but we are limited one thread architecture.
>>
>> regards
>> Pavel Stehule
>>
>
> Yeah, this would be pretty the same.
>
> I just didn't understand if this is already implemented in PG ?
>

no - I have workin prototype now - and I am searching sponsors for
finishing this work.

http://okbob.blogspot.com/2007/11/stacked-recordset-multirecordset.html
http://okbob.blogspot.com/2007/11/first-real-procedures-on-postgresql.html

But it's really similar to what do you want and it's can be
interesting together with plpgpsm for you, because plpgpsm (SQL/PSM)
allows one statement procedures, like:

create procedure foo(...) as $$
select * from tab;
$$ language plpgpsm;

so this is standard syntax for persistent prepared statement :)

regards
Pavel Stehule



> I've tried to create a PROCEDURE in QueryTool of pgAdminIII and I get
> following result:
>
> ERROR:  syntax error at or near "PROCEDURE"
> LINE 1: CREATE PROCEDURE aatestubnd(refcursor, insklid integer, inda...
>               ^
>
> ********** Error **********
>
> ERROR: syntax error at or near "PROCEDURE"
> SQL state: 42601
> Character: 8
>
>
> If I try with CREATE FUNCTION I get this result (as expected):
>
> ERROR:  function result type must be specified
>
> ********** Error **********
>
> ERROR: function result type must be specified
> SQL state: 42P13
>
>
> Is this because of QueryTool's limitations or is this feature not yet
> implemented in Postgre ?
>
> Though, CREATE PROCEDURE should be a valid SQL 92 standard procedure.
>
> Best regards,
>
> Milan Oparnica
>
> --
> Sent via pgsql-sql mailing list (pgsql-sql@postgresql.org)
> To make changes to your subscription:
> http://www.postgresql.org/mailpref/pgsql-sql
>


Re: PERSISTANT PREPARE (another point of view)

From
Milan Oparnica
Date:
chester c young wrote:

>    Session #1 has search_path=schema1
>    Session #2 has search_path=schema2
> if session #1 attempts to exec stmt, it prepare and use schema1
> if session #2 attempts to use stmt, if prepared globally, disaster
> 

I'm sorry, I wasn't precise enough. When I said global I meant global in 
Schema scope. Just like standard stored procedures are.

Did you see post from Mr.Pavel.Stehule about PROCEDURES ?
Such implementation would have the same effect as global prepare.
If it could even support nesting (calling procedure from within another 
procedure).

Let's hope he does his implementation in 8.4.

Regards,

Milan Oparnica