Thread: What's faster? BEGIN ... EXCEPTION or CREATE TEMP TABLE IF NOT EXISTS?
I am working on an audit logging trigger that gets called for every row inserted, updated or deleted on any table.
For this, I need to store a couple of temporary session variables such as the ID of the user performing the change, which can be set at the start of the session.
Until now I have been using a permanent table to store the session variables, but it has been difficult to wipe the data properly at the end of the session.
So I have decided to try to implement them using temporary tables.
The problem now is that for every row now, I need to check for the existence of the temporary table before I access it, in order to avoid exceptions.
Either I can do all such accesses within a BEGIN...EXCEPTION block, or I can precede any such accesses with CREATE TEMP TABLE IF NOT EXISTS.
Is one of these much faster than the other? Will I be slowing things down inordinately by doing this for every row?
Thanks.
--
Moshe Jacobson
Nead Werx, Inc. | Senior Systems Engineer
Nead Werx, Inc. | Senior Systems Engineer
2323 Cumberland Parkway, Suite 201 | Atlanta, GA 30339
moshe@neadwerx.com | www.neadwerx.com
moshe@neadwerx.com | www.neadwerx.com
Re: What's faster? BEGIN ... EXCEPTION or CREATE TEMP TABLE IF NOT EXISTS?
From
Merlin Moncure
Date:
On Mon, Oct 1, 2012 at 8:36 AM, Moshe Jacobson <moshe@neadwerx.com> wrote: > I am working on an audit logging trigger that gets called for every row > inserted, updated or deleted on any table. > For this, I need to store a couple of temporary session variables such as > the ID of the user performing the change, which can be set at the start of > the session. > Until now I have been using a permanent table to store the session > variables, but it has been difficult to wipe the data properly at the end of > the session. > So I have decided to try to implement them using temporary tables. > > The problem now is that for every row now, I need to check for the existence > of the temporary table before I access it, in order to avoid exceptions. > Either I can do all such accesses within a BEGIN...EXCEPTION block, or I can > precede any such accesses with CREATE TEMP TABLE IF NOT EXISTS. > Is one of these much faster than the other? Will I be slowing things down > inordinately by doing this for every row? Couple points: *) Functions without exception blocks are faster than those with. *) Therefore, CREATE/IF NOT EXISTS is probably faster (test to be sure) *) Carefully consider if you you will ever in the future introduce connection pooling. If you do, relying on session scoped objects like temp tables is probably not a good idea. *) You can rig permanent tables around pg_backend_pid(). On session login, clear session private records that have your pid (if any). Transaction temporary data can be similarly rigged around txid_current() with an even simpler maintenance process. merlin
Re: What's faster? BEGIN ... EXCEPTION or CREATE TEMP TABLE IF NOT EXISTS?
From
Moshe Jacobson
Date:
Merlin,
On Mon, Oct 1, 2012 at 10:28 AM, Merlin Moncure <mmoncure@gmail.com> wrote:
Couple points:
*) Functions without exception blocks are faster than those with.
Clearly.
*) Therefore, CREATE/IF NOT EXISTS is probably faster (test to be sure)
I don't think that can be assumed by your premise above. Essentially we are comparing the price of starting an exception block against checking the catalog for a table.
*) Carefully consider if you you will ever in the future introduce
connection pooling. If you do, relying on session scoped objects like
temp tables is probably not a good idea.
We already use connection pooling with pgbouncer, but upon disconnect, it issues a DISCARD ALL statement, which should take care of this.
*) You can rig permanent tables around pg_backend_pid(). On session
login, clear session private records that have your pid (if any).
Transaction temporary data can be similarly rigged around
txid_current() with an even simpler maintenance process.
We currently do use permanent tables using pg_backend_pid(). It's because of the connection pooling specifically that we are having problems with stale data. I have been unable to find a way to automatically clear that data upon start or end of a session, or at least check if it's been set in this session or not.
--
Moshe Jacobson
Nead Werx, Inc. | Senior Systems Engineer
Nead Werx, Inc. | Senior Systems Engineer
2323 Cumberland Parkway, Suite 201 | Atlanta, GA 30339
moshe@neadwerx.com | www.neadwerx.com
moshe@neadwerx.com | www.neadwerx.com
Re: What's faster? BEGIN ... EXCEPTION or CREATE TEMP TABLE IF NOT EXISTS?
From
Merlin Moncure
Date:
On Mon, Oct 1, 2012 at 10:21 AM, Moshe Jacobson <moshe@neadwerx.com> wrote: > Merlin, > > On Mon, Oct 1, 2012 at 10:28 AM, Merlin Moncure <mmoncure@gmail.com> wrote: >> >> >> Couple points: >> *) Functions without exception blocks are faster than those with. > > > Clearly. > >> >> *) Therefore, CREATE/IF NOT EXISTS is probably faster (test to be sure) > > > I don't think that can be assumed by your premise above. Essentially we are > comparing the price of starting an exception block against checking the > catalog for a table. A vanilla create table has to scan the catalogs also. >> *) Carefully consider if you you will ever in the future introduce >> connection pooling. If you do, relying on session scoped objects like >> temp tables is probably not a good idea. > > We already use connection pooling with pgbouncer, but upon disconnect, it > issues a DISCARD ALL statement, which should take care of this. Especially if you're using pgbouncer transaction mode, using temporary tables is probably not a good idea. When you DISCARD them, it invalidates all your function plans which is going to be painful if you have a lot of pl/pgsql (test any non-trivial pl/pgsql routine and you'll see it's much slower on the first invocation). Also, if you need to share data between transactions, it's not clear how you're organizing such that different application sessions are going to tromp over each other's data. >> *) You can rig permanent tables around pg_backend_pid(). On session >> login, clear session private records that have your pid (if any). >> Transaction temporary data can be similarly rigged around >> txid_current() with an even simpler maintenance process. > > We currently do use permanent tables using pg_backend_pid(). It's because of > the connection pooling specifically that we are having problems with stale > data. I have been unable to find a way to automatically clear that data upon > start or end of a session, or at least check if it's been set in this > session or not. IMO the right way to do it is to generate a unique application token (sequence is ok if you're not worried about it being guessed) when your application session logs in. That token should be passed into *all* your session specific backend functions and can be used to organize session specific temporary data in your permanent tables. To deal with ungraceful application client exit, you can consider implementing an on_proc_exit handler to close the session down so that it can be appropriately cleaned up (there are severe limits to the SQL you can execute in the handler but you can make dblink calls). If some of them still sneak through, periodic sweep on stale pids against pg_stat_activity should take care of them. Note, if your users have some type of unique identifier (like a login or an email) and if they are only allowed to have one active session at a time, you can organize your session data around that instead of generating a token. merlin
Re: What's faster? BEGIN ... EXCEPTION or CREATE TEMP TABLE IF NOT EXISTS?
From
Merlin Moncure
Date:
On Mon, Oct 1, 2012 at 11:22 AM, Merlin Moncure <mmoncure@gmail.com> wrote: >> We currently do use permanent tables using pg_backend_pid(). It's because of >> the connection pooling specifically that we are having problems with stale >> data. I have been unable to find a way to automatically clear that data upon >> start or end of a session, or at least check if it's been set in this >> session or not. > > IMO the right way to do it is to generate a unique application token > (sequence is ok if you're not worried about it being guessed) when > your application session logs in. That token should be passed into > *all* your session specific backend functions and can be used to > organize session specific temporary data in your permanent tables. > > To deal with ungraceful application client exit, you can consider > implementing an on_proc_exit handler to close the session down so that actually, you can't do that (on_proc_exit or scan for pids) if you're using transaction mode connection pooling. In our case, we modified pgbouncer to pass async notifications and would have used that to periodically scan connected clients if we didn't have the luxury of one client/session only. merlin
Re: What's faster? BEGIN ... EXCEPTION or CREATE TEMP TABLE IF NOT EXISTS?
From
Moshe Jacobson
Date:
On Mon, Oct 1, 2012 at 12:22 PM, Merlin Moncure <mmoncure@gmail.com> wrote:
--
>> *) Functions without exception blocks are faster than those with.A vanilla create table has to scan the catalogs also.
>> *) Therefore, CREATE/IF NOT EXISTS is probably faster (test to be sure)
>
> I don't think that can be assumed by your premise above. Essentially we are
> comparing the price of starting an exception block against checking the
> catalog for a table.
Yes but that is irrelevant to the discussion. I am comparing the speed of repeated table existence checks with the speed of repeated exception blocks that access said table.
> We already use connection pooling with pgbouncer, but upon disconnect, itEspecially if you're using pgbouncer transaction mode, using temporary
> issues a DISCARD ALL statement [...]
tables is probably not a good idea.
We are using it in session mode, so none of that is relevant to my situation.
>> *) You can rig permanent tables around pg_backend_pid(). [...]IMO the right way to do it is to generate a unique application token
>
> We currently do use permanent tables using pg_backend_pid(). It's because of
> the connection pooling specifically that we are having problems with stale
> data. I have been unable to find a way to automatically clear that data upon
> start or end of a session, or at least check if it's been set in this
> session or not.
[...] when your application session logs in. That token should be passed into
*all* your session specific backend functions [...]
No, this will not work because the backend functions are trigger functions, so they cannot be passed this data.
Thanks.
Moshe Jacobson
Nead Werx, Inc. | Senior Systems Engineer
Nead Werx, Inc. | Senior Systems Engineer
2323 Cumberland Parkway, Suite 201 | Atlanta, GA 30339
moshe@neadwerx.com | www.neadwerx.com
moshe@neadwerx.com | www.neadwerx.com
Re: What's faster? BEGIN ... EXCEPTION or CREATE TEMP TABLE IF NOT EXISTS?
From
Merlin Moncure
Date:
On Mon, Oct 1, 2012 at 3:58 PM, Moshe Jacobson <moshe@neadwerx.com> wrote: > On Mon, Oct 1, 2012 at 12:22 PM, Merlin Moncure <mmoncure@gmail.com> wrote: >> >> >> *) Functions without exception blocks are faster than those with. >> >> *) Therefore, CREATE/IF NOT EXISTS is probably faster (test to be sure) >> > >> > I don't think that can be assumed by your premise above. Essentially we >> > are >> > comparing the price of starting an exception block against checking the >> > catalog for a table. >> >> A vanilla create table has to scan the catalogs also. > > > Yes but that is irrelevant to the discussion. I am comparing the speed of > repeated table existence checks with the speed of repeated exception blocks > that access said table. Both approaches have to do a catalog scan (even if you've established an exception block the server still internally has to do a catalog scan in order to raise an appropriate error). The exception block has the additional overhead of a subtransaction. >> > We already use connection pooling with pgbouncer, but upon disconnect, >> > it >> > issues a DISCARD ALL statement [...] >> >> Especially if you're using pgbouncer transaction mode, using temporary >> tables is probably not a good idea. > > We are using it in session mode, so none of that is relevant to my > situation. OK. (but I don't like solutions that prevent stateless connection pooling). In just about all cases where scalability was a concern and I used session scoped objects I ended up regretting it somewhere down the line. A more stateless approach has a lot of advantages besides supporting more aggressive connection pooling -- for example you can restart the server and all your connected clients wont lose local temporary data. Anyways, enough lecturing -- I'm sure you've got things pretty well figured out :-). >> >> *) You can rig permanent tables around pg_backend_pid(). [...] >> >> > >> > We currently do use permanent tables using pg_backend_pid(). It's >> > because of >> > the connection pooling specifically that we are having problems with >> > stale >> > data. I have been unable to find a way to automatically clear that data >> > upon >> > start or end of a session, or at least check if it's been set in this >> > session or not. >> >> IMO the right way to do it is to generate a unique application token >> [...] when your application session logs in. That token should be passed >> into >> *all* your session specific backend functions [...] > > > No, this will not work because the backend functions are trigger functions, > so they cannot be passed this data. Sure they can...there are a number of ways to do it (although they all require A. an extra round trip to establish the ID for later statements in the transaction to read or B. a wrapping function that handles the work on the server side). That said, if you're super duper sure you'll never use transaction mode pooling, Temp tables are ok to use unless your sessions are quite short (in which case all the plan invalidation flying around will start to hurt). merlin
Re: What's faster? BEGIN ... EXCEPTION or CREATE TEMP TABLE IF NOT EXISTS?
From
Moshe Jacobson
Date:
On Tue, Oct 2, 2012 at 9:18 AM, Merlin Moncure <mmoncure@gmail.com> wrote:
OK this makes sense. Thanks :-) I will go for the CREATE TABLE approach.
--
> Yes but that is irrelevant to the discussion. I am comparing the speed ofBoth approaches have to do a catalog scan (even if you've established
> repeated table existence checks with the speed of repeated exception blocks
> that access said table.
an exception block the server still internally has to do a catalog
scan in order to raise an appropriate error). The exception block has
the additional overhead of a subtransaction.
OK this makes sense. Thanks :-) I will go for the CREATE TABLE approach.
Moshe Jacobson
Nead Werx, Inc. | Senior Systems Engineer
Nead Werx, Inc. | Senior Systems Engineer
2323 Cumberland Parkway, Suite 201 | Atlanta, GA 30339
moshe@neadwerx.com | www.neadwerx.com
moshe@neadwerx.com | www.neadwerx.com
On 01/10/2012 15:36, Moshe Jacobson wrote: > I am working on an audit logging trigger that gets called for every row > inserted, updated or deleted on any table. > For this, I need to store a couple of temporary session variables such as > the ID of the user performing the change, which can be set at the start of > the session. > Until now I have been using a permanent table to store the session > variables, but it has been difficult to wipe the data properly at the end > of the session. Do you know about session variables? I did something similar to what you are describing and it ended up much simpler than using tables, temporary or not. You need to configure them in postgresql.conf, e.g.: custom_variable_classes = 'myapp' Then in the application code: SET myapp.uid = 42; And in the pl/pgsql function: CREATE OR REPLACE FUNCTION dblog() RETURNS TRIGGER AS $$ DECLARE uid INTEGER; BEGIN BEGIN SELECT current_setting('myapp.uid') INTO uid; EXCEPTION WHEN undefined_object THEN uid = null; WHEN data_exception THEN uid = null; END; ... END; $$ LANGUAGE plpgsql; The major benefit here is that it doesn't touch the table engines, temporary or not.
Attachment
Re: Re: What's faster? BEGIN ... EXCEPTION or CREATE TEMP TABLE IF NOT EXISTS?
From
Moshe Jacobson
Date:
On Thu, Oct 4, 2012 at 6:12 AM, Ivan Voras <ivoras@freebsd.org> wrote:
This sounds incredibly useful. Why have I not heard of this until today??
On 01/10/2012 15:36, Moshe Jacobson wrote:Do you know about session variables?
> I am working on an audit logging trigger that gets called for every row
> inserted, updated or deleted on any table.
> For this, I need to store a couple of temporary session variables such as
> the ID of the user performing the change, which can be set at the start of
> the session.
The major benefit here is that it doesn't touch the table engines,
temporary or not.
This sounds incredibly useful. Why have I not heard of this until today??
In your example you still had to use a BEGIN...EXCEPTION block. Is that faster than a create temp table?
--
Moshe Jacobson
Nead Werx, Inc. | Senior Systems Engineer
Nead Werx, Inc. | Senior Systems Engineer
2323 Cumberland Parkway, Suite 201 | Atlanta, GA 30339
moshe@neadwerx.com | www.neadwerx.com
moshe@neadwerx.com | www.neadwerx.com
Re: Re: What's faster? BEGIN ... EXCEPTION or CREATE TEMP TABLE IF NOT EXISTS?
From
Ivan Voras
Date:
On 5 October 2012 04:53, Moshe Jacobson <moshe@neadwerx.com> wrote: > On Thu, Oct 4, 2012 at 6:12 AM, Ivan Voras <ivoras@freebsd.org> wrote: >> >> On 01/10/2012 15:36, Moshe Jacobson wrote: >> > I am working on an audit logging trigger that gets called for every row >> > inserted, updated or deleted on any table. >> > For this, I need to store a couple of temporary session variables such >> > as >> > the ID of the user performing the change, which can be set at the start >> > of >> > the session. >> >> Do you know about session variables? >> The major benefit here is that it doesn't touch the table engines, >> temporary or not. > > This sounds incredibly useful. Why have I not heard of this until today?? > In your example you still had to use a BEGIN...EXCEPTION block. Is that > faster than a create temp table? I think I can make a fairly educated guess that catching exceptions while dealing with session variables should be much, much faster than creating any kind of a table :) Besides, from what you said, you will ensure on the app level that the session variable is set sometime close to when you open a connection to Pg, so the "catch" part of the exception block will probably not run at all.
Re: Re: What's faster? BEGIN ... EXCEPTION or CREATE TEMP TABLE IF NOT EXISTS?
From
Merlin Moncure
Date:
On Fri, Oct 5, 2012 at 3:09 AM, Ivan Voras <ivoras@freebsd.org> wrote: > I think I can make a fairly educated guess that catching exceptions > while dealing with session variables should be much, much faster than > creating any kind of a table :) That is true, but it's not clear how using session variables keeps you from having to create the table. If the table is already there, a session variable guarding the table construction shouldn't be any faster/better than a simple 'create if not exists'. A catalog scan is basically boils down to a query. So I'm not sure that actually helps. On the other hand, if the temp table can be completely ditched for a session variable or two, then yeah, that would be much better since you'd avoid the overhead of creating the table completely. merlin
Re: Re: What's faster? BEGIN ... EXCEPTION or CREATE TEMP TABLE IF NOT EXISTS?
From
Ivan Voras
Date:
On 5 October 2012 15:55, Merlin Moncure <mmoncure@gmail.com> wrote: > On Fri, Oct 5, 2012 at 3:09 AM, Ivan Voras <ivoras@freebsd.org> wrote: >> I think I can make a fairly educated guess that catching exceptions >> while dealing with session variables should be much, much faster than >> creating any kind of a table :) > On the other hand, if the temp table can be completely ditched for a > session variable or two, then yeah, that would be much better since > you'd avoid the overhead of creating the table completely. Yes, this is what I was aiming at, based on the OP mentioning he only has a limited amount of data to manage in this way.
Re: Re: What's faster? BEGIN ... EXCEPTION or CREATE TEMP TABLE IF NOT EXISTS?
From
Moshe Jacobson
Date:
On Fri, Oct 5, 2012 at 11:13 AM, Ivan Voras <ivoras@freebsd.org> wrote:
> On the other hand, if the temp table can be completely ditched for a> session variable or two, then yeah, that would be much better sinceYes, this is what I was aiming at, based on the OP mentioning he only
> you'd avoid the overhead of creating the table completely.
has a limited amount of data to manage in this way.
Yup, I'm going to see how this goes using session variables. I think it is exactly what I need. Thanks!
Moshe Jacobson
Nead Werx, Inc. | Senior Systems Engineer
Nead Werx, Inc. | Senior Systems Engineer
2323 Cumberland Parkway, Suite 201 | Atlanta, GA 30339
moshe@neadwerx.com | www.neadwerx.com
moshe@neadwerx.com | www.neadwerx.com