views:

65

answers:

3

postgres 8.3 / Ubuntu Karmic / 32-bit (in virtualbox):

  duration: 76.534 ms  statement: truncate audit.users cascade
  duration: 0.952 ms  statement: delete from audit.users

postgres 8.4 / Ubuntu lucid / 64-bit (native, on the machine hosting the karmic virtualbox):

  duration: 1469.271 ms  statement: truncate audit.users cascade
  duration: 0.988 ms  statement: delete from audit.users

So the DELETE statements are pretty much equivalent, but TRUNCATE takes 20x longer on one platform than the other. EXPLAIN doesn't seem to work on TRUNCATE. How do I find out what's taking so long?

Edited to add:

The above samples were taken when there was another idle connection open to the database, but no open transactions or other activity. I use TRUNCATE in the tearDown method of some automated tests, which is where I noticed the speed difference between platforms.

+1  A: 

TRUNCATE needs a lock, setting this lock, might take some time because of other transactions. Try pg_locks to see what's going on.

Frank Heikens
Is there a way to log lock events instead of polling for them with pg_locks? The case where it takes < 100ms it's difficult to get an accurate reading of how many locks it has. The case where it takes longer, there are over 70 locks at peak.
keturn
Set a manual LOCK with NO WAIT if you don't want to wait: http://www.postgresql.org/docs/8.4/static/sql-lock.html
Frank Heikens
Adjust log_lock_waits if you want to, as the name says, log lock waits: http://www.postgresql.org/docs/current/static/runtime-config-logging.html
Greg Smith
A: 

truncate needs to lock the whole table. If there are any transactions running, it needs to wait for them to finish. Another side effect which is not evidenced here is that its a single bottleneck preventing any new transactions which need this table.

When it's a live system with dozens or hundreds of transactions using this table, this bottleneck itself may be an important issue. delete only locks single rows, so it's faster in many concurrent/live environments.

I'm not sure what you need this for, but you may want to build new "version" of data for this table to a temporary table, then (to keep lock/update time as short as possible) push it to the live table with delete + insert as select:

begin;

create temp table my_data on commit drop as
---... lengthy calculation here;

delete from data;

insert into data select * from my_data;

commit;
Konrad Garus
I edited my question to provide a little more context; the timings I gave are not from an application with lots of concurrency, they're from an idle system.
keturn
Now that's weird. I would research the immediate locks Frank suggested or try asking at PG mailing lists.
Konrad Garus
+1  A: 

The way TRUNCATE works in PostgreSQL, it's very sensitive to how fast your filesystem can delete blocks, as well as whether it correctly honors the fsync system call when you write to flush the write cache out. My guess is that you have different filesystem setups on the two systems. For example, if the Lucid install is using ext4 and the Karmic one ext3, this is unsurprising behavior. Newer kernels will correctly turn fsync calls into disk cache flushing via write barriers; older ones let the drives lie to them about things being written. This is a good thing in terms of keeping the database writes safe during a crash, but performance drops a lot when the kernel does the right thing from a reliability perspective.

Greg Smith
This was it. Turning `fsync = off` on the slow system makes it as fast as the other one. Maybe virtualbox doesn't really do fsync or something.
keturn