Re: Very Poor Insert Performance

From: Damien Dougan <damien(dot)dougan(at)mobilecohesion(dot)com>
To: pgsql-performance(at)postgresql(dot)org
Cc: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
Subject: Re: Very Poor Insert Performance
Date: 2003-10-29 10:22:24
Message-ID: 200310291022.24035.damien.dougan@mobilecohesion.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-performance

On Monday 27 October 2003 8:12 pm, Tom Lane wrote:
> Damien Dougan <damien(dot)dougan(at)mobilecohesion(dot)com> writes:
> > Has anyone any ideas as to what could be causing the spiraling
> > performance?
>
> You really haven't provided any information that would allow anything
> but guesses, but I'll guess anyway: poor plans for foreign key checks?
> See nearby threads.
>
> regards, tom lane

Apologies for not including more info - I had been hoping that spiralling performance was a known tell-tale sign of something :)

Here is some additional information - sorry if its overload, but I figured I should give an intro to the schema before showing the EXPLAIN results!

Firstly, a quick schema overview for the relevant tables:

contact has many contactparts
address has many addressparts
contact has many address

Now, the above table relationships are connected via relationship tables (rather than foreign indexes directly to each other), so we have:

contact
rel_contact_has_contactpart
address
rel_address_has_addresspart

(The reasons behind this are for meta-data purposes - our database is intended to be very abstract from the code...)

Table "public.contact"
Column | Type | Modifiers
------------------+-----------------------------+---------------------------------------------------
id | integer | default nextval('contact_id_seq'::text)
version | integer | default 1
contactid | character varying |
enddate | timestamp without time zone |
preferredaddress | character varying |
startdate | timestamp without time zone |
Indexes:
"contact_id_idx" unique, btree (id)
"contact_key" unique, btree (contactid)

So we have an index on the meta-data related "id" and the externally visible "contactid" values. The "id" is used with the rel_contact_has_XXX tables (see below).

Table "public.contactpart"
Column | Type | Modifiers
-------------+-------------------+------------------------------------------------
id | integer | default nextval('contactpart_id_seq'::text)
version | integer | default 1
detailname | character varying | not null
detailvalue | character varying |
Indexes:
"contactpart_id_idx" unique, btree (id)

So we have an index on the meta-data related "id".


Table "public.address"
Column | Type | Modifiers
---------+-----------------------------+--------------------------------------------
id | integer | default nextval('mc_address_id_seq'::text)
version | integer | default 1
enddate | timestamp without time zone |
format | character varying |
type | character varying | not null
value | character varying |
Indexes:
"address_id_idx" unique, btree (id)
"address_value_key" btree (value)

So we have an index on the meta-data related "id".

Table "public.addresspart"
Column | Type | Modifiers
-------------+-------------------+------------------------------------------------
id | integer | default nextval('addresspart_id_seq'::text)
version | integer | default 1
detailname | character varying | not null
detailvalue | character varying |
Indexes:
"addresspart_id_idx" unique, btree (id)

So we have an index on the meta-data related "id". This is used with the rel_address_has_addresspart table (see below).


Table "public.rel_contact_has_contactpart"
Column | Type | Modifiers
----------------------+---------+-----------
contact_id | integer |
contactpart_id | integer |
Indexes:
"rel_contact_has_contactpart_idx2" unique, btree (contactpart_id)
"rel_contact_has_contactpart_idx1" btree (contact_id)

So we have a unique index on the contactpart and a non-unique index on the contact (to reflect the 1:M relationship contact has contactparts)

Table "public.rel_address_has_addresspart"
Column | Type | Modifiers
-------------------+---------+-----------
address_id | integer |
addresspart_id | integer |
Indexes:
"rel_address_has_addresspart_idx2" unique, btree (addresspart_id)
"rel_address_has_addresspart_idx1" btree (address_id)

So we have a unique index on the addresspart and a non-unique index on the address (to reflect the 1:M relationship address has addressparts)


Table "public.rel_contact_has_address"
Column | Type | Modifiers
----------------------+---------+-----------
contact_id | integer |
address_id | integer |
Indexes:
"rel_contact_has_address_idx2" unique, btree (address_id)
"rel_contact_has_address_idx1" btree (contactdetails_id)

So we have a unique index on the address and a non-unique index on the contact (to reflect the 1:M relationship contact has addresses)

However, to add a layer of abstraction to the business logic, the underlying tables are never directly exposed through anything other than public views. The public views combine the <table> and <tablepart> into a single table.

So we have 2 public views: PvContact which ties together the contact and contactparts, and PvAddress which ties together the address and addresspart.

View "public.pvcontact"
Column | Type | Modifiers
------------------+-----------------------------+-----------
version | integer |
contactid | character varying |
startdate | timestamp without time zone |
enddate | timestamp without time zone |
preferredaddress | character varying |
firstname | character varying |
lastname | character varying |

(Note - firstname and lastname are dervied from the detailnames of contactpart table)

View "public.pvaddress"
Column | Type | Modifiers
-----------+-----------------------------+-----------
version | integer |
contactid | character varying |
type | character varying |
format | character varying |
enddate | timestamp without time zone |
npi | character varying |
ton | character varying |
number | character varying |
prefix | character varying |
addrvalue | character varying |
link | character varying |
house | character varying |
street | character varying |
town | character varying |
city | character varying |
county | character varying |
postcode | character varying |
state | character varying |
zipcode | character varying |
extension | character varying |

(Note - number, prefix, link, house, street, town, city, postcode etc are derived from the detailnames of addresspart table)

For example, suppose we have 2 contactparts for a particular contact (with unique id = y): FirstName and LastName, then the contactpart table would have 2 rows like:

id = x
version = 1
partname = 'FirstName'
partvalue = 'John'

id = x+1
version = 1
partname = 'LastName'
partvalue = 'Doe'

Then the public view, PvContact, would look like:

Version = 1
ContactId = y
StartDate = ...
EndDate = ...
PreferredAddress = ...
FirstName = John
LastName = Doe

All Create, Read, Update, Delete operations on the DB are performed by StoredProcedures (again, to help abstract the code from the DB). The SPs are capable of dealing with externally (public view) advertised schemas, and ensuring data integrity across the underlying tables.

Now, our problem seems to be the delays introduced by reading from the public views. I've taken some measurements of raw INSERTS that mirror what the SPs are doing (but the data is invalid and its not correctly linked across tables (which is what the StoredProcs are responsible for) - but the INSERTS are happening in the same order and frequency for a valid data upload). We can upload 2000 sets of users+contacts+addresses in about 17 seconds. But when it is done via the Stored Procedures (which do some inserts, some reads, some more inserts etc to ensure tables are properly linked via the relationships), this drops to 2 minutes for 2000. And the performance spirals down to less than 1 user+contact+address per second after a short while.

First of all then, the definition of the PublicView PvAddress

View definition:
SELECT address.id AS addressid, address."version", contact.id AS contactid, contact.contactid AS contactuuid, address."type", address.format, address.enddate, address.value, rel_npi.npiid, rel_npi.npi, rel_ton.tonid, rel_ton.ton, rel_number.numberid, rel_number.number, rel_prefix.prefixid, rel_prefix.prefix, rel_addrvalue.addrvalueid, rel_addrvalue.addrvalue, rel_link.linkid, rel_link.link, rel_house.houseid, rel_house.house, rel_street.streetid, rel_street.street, rel_town.townid, rel_town.town, rel_city.cityid, rel_city.city, rel_county.countyid, rel_county.county, rel_postcode.postcodeid, rel_postcode.postcode, rel_state.stateid, rel_state.state, rel_zipcode.zipcodeid, rel_zipcode.zipcode, rel_extension.extensionid, rel_extension.extension
FROM svcurrentcontactdetails contact, rel_contact_has_address rel_contact, svcurrentaddress address
LEFT JOIN ( SELECT rel.address_id AS addressid, rel.addresspart_id AS npiid, det.detailvalue AS npi
FROM rel_address_has_addresspart rel, addresspart det
WHERE rel.addresspart_id = det.id AND det.detailname::text = 'Npi'::text) rel_npi ON address.id = rel_npi.addressid
LEFT JOIN ( SELECT rel.address_id AS addressid, rel.addresspart_id AS tonid, det.detailvalue AS ton
FROM rel_address_has_addresspart rel, addresspart det
WHERE rel.addresspart_id = det.id AND det.detailname::text = 'Ton'::text) rel_ton ON address.id = rel_ton.addressid
LEFT JOIN ( SELECT rel.address_id AS addressid, rel.addresspart_id AS numberid, det.detailvalue AS number
FROM rel_address_has_addresspart rel, addresspart det
WHERE rel.addresspart_id = det.id AND det.detailname::text = 'Number'::text) rel_number ON address.id = rel_number.addressid
LEFT JOIN ( SELECT rel.address_id AS addressid, rel.addresspart_id AS prefixid, det.detailvalue AS prefix
FROM rel_address_has_addresspart rel, addresspart det
WHERE rel.addresspart_id = det.id AND det.detailname::text = 'Prefix'::text) rel_prefix ON address.id = rel_prefix.addressid
LEFT JOIN ( SELECT rel.address_id AS addressid, rel.addresspart_id AS addrvalueid, det.detailvalue AS addrvalue
FROM rel_address_has_addresspart rel, addresspart det
WHERE rel.addresspart_id = det.id AND det.detailname::text = 'AddrValue'::text) rel_addrvalue ON address.id = rel_addrvalue.addressid
LEFT JOIN ( SELECT rel.address_id AS addressid, rel.addresspart_id AS linkid, det.detailvalue AS link
FROM rel_address_has_addresspart rel, addresspart det
WHERE rel.addresspart_id = det.id AND det.detailname::text = 'Link'::text) rel_link ON address.id = rel_link.addressid
LEFT JOIN ( SELECT rel.address_id AS addressid, rel.addresspart_id AS houseid, det.detailvalue AS house
FROM rel_address_has_addresspart rel, addresspart det
WHERE rel.addresspart_id = det.id AND det.detailname::text = 'House'::text) rel_house ON address.id = rel_house.addressid
LEFT JOIN ( SELECT rel.address_id AS addressid, rel.addresspart_id AS streetid, det.detailvalue AS street
FROM rel_address_has_addresspart rel, addresspart det
WHERE rel.addresspart_id = det.id AND det.detailname::text = 'Street'::text) rel_street ON address.id = rel_street.addressid
LEFT JOIN ( SELECT rel.address_id AS addressid, rel.addresspart_id AS townid, det.detailvalue AS town
FROM rel_address_has_addresspart rel, addresspart det
WHERE rel.addresspart_id = det.id AND det.detailname::text = 'Town'::text) rel_town ON address.id = rel_town.addressid
LEFT JOIN ( SELECT rel.address_id AS addressid, rel.addresspart_id AS cityid, det.detailvalue AS city
FROM rel_address_has_addresspart rel, addresspart det
WHERE rel.addresspart_id = det.id AND det.detailname::text = 'City'::text) rel_city ON address.id = rel_city.addressid
LEFT JOIN ( SELECT rel.address_id AS addressid, rel.addresspart_id AS countyid, det.detailvalue AS county
FROM rel_address_has_addresspart rel, addresspart det
WHERE rel.addresspart_id = det.id AND det.detailname::text = 'County'::text) rel_county ON address.id = rel_county.addressid
LEFT JOIN ( SELECT rel.address_id AS addressid, rel.addresspart_id AS postcodeid, det.detailvalue AS postcode
FROM rel_address_has_addresspart rel, addresspart det
WHERE rel.addresspart_id = det.id AND det.detailname::text = 'Postcode'::text) rel_postcode ON address.id = rel_postcode.addressid
LEFT JOIN ( SELECT rel.address_id AS addressid, rel.addresspart_id AS stateid, det.detailvalue AS state
FROM rel_address_has_addresspart rel, addresspart det
WHERE rel.addresspart_id = det.id AND det.detailname::text = 'State'::text) rel_state ON address.id = rel_state.addressid
LEFT JOIN ( SELECT rel.address_id AS addressid, rel.addresspart_id AS zipcodeid, det.detailvalue AS zipcode
FROM rel_address_has_addresspart rel, addresspart det
WHERE rel.addresspart_id = det.id AND det.detailname::text = 'Zipcode'::text) rel_zipcode ON address.id = rel_zipcode.addressid
LEFT JOIN ( SELECT rel.address_id AS addressid, rel.addresspart_id AS extensionid, det.detailvalue AS extension
FROM rel_address_has_addresspart rel, addresspart det
WHERE rel.addresspart_id = det.id AND det.detailname::text = 'Extension'::text) rel_extension ON address.id = rel_extension.addressid
WHERE contact.id = rel_contact.contact_id AND address.id = rel_contact.address_id;

(The JOINs are where our problems are below ...)

hydradb=# explain select * from pvaddress where contactuuid = 'test' and type = 'sms' and format is null ;
QUERY PLAN

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-----------------------------------------------
Merge Join (cost=42499.93..44975.38 rows=1 width=358)
Merge Cond: ("outer".id = "inner".address_id)
-> Merge Left Join (cost=42491.11..44957.05 rows=3795 width=323)
Merge Cond: ("outer".id = "inner".address_id)
-> Merge Left Join (cost=41822.20..44278.07 rows=3795 width=305)
Merge Cond: ("outer".id = "inner".address_id)
-> Merge Left Join (cost=41153.29..43599.08 rows=3795 width=287)
Merge Cond: ("outer".id = "inner".address_id)
-> Merge Left Join (cost=40484.39..42920.10 rows=3795 width=269)
Merge Cond: ("outer".id = "inner".address_id)
-> Merge Left Join (cost=39815.48..42241.12 rows=3795 width=251)
Merge Cond: ("outer".id = "inner".address_id)
-> Merge Left Join (cost=39146.58..41562.13 rows=3795 width=233)
Merge Cond: ("outer".id = "inner".address_id)
-> Merge Left Join (cost=38477.67..40883.15 rows=3795 width=215)
Merge Cond: ("outer".id = "inner".address_id)
-> Merge Left Join (cost=37808.76..40204.16 rows=3795 width=197)
Merge Cond: ("outer".id = "inner".address_id)
-> Merge Left Join (cost=37139.86..39525.18 rows=3795 width=179)
Merge Cond: ("outer".id = "inner".address_id)
-> Merge Left Join (cost=36470.95..38846.20 rows=3795 width=161)
Merge Cond: ("outer".id = "inner".address_id)
-> Merge Left Join (cost=35802.04..38167.21 rows=3795 width=143)
Merge Cond: ("outer".id = "inner".address_id)
-> Merge Left Join (cost=28634.40..30852.70 rows=3795 width=125)
Merge Cond: ("outer".id = "inner".address_id)
-> Merge Left Join (cost=21495.85..23569.10 rows=3795 width=107)
Merge Cond: ("outer".id = "inner".address_id)
-> Merge Left Join (cost=14328.21..16254.59 rows=3795 width=89)
Merge Cond: ("outer".id = "inner".address_id)
-> Merge Left Join (cost=7102.23..8878.06 rows=3795 width=71)
Merge Cond: ("outer".id = "inner".address_id)
-> Index Scan using address_id_idx on address (cost=0.00..1633.07 rows=3795 width=53)
Filter: (((enddate IS NULL) OR (('now'::text)::timestamp(6) with time zone < (enddate)::timestamp with time zone)) AND (("typ
e")::text = 'sms'::text) AND (format IS NULL))
-> Sort (cost=7102.23..7159.65 rows=22970 width=22)
Sort Key: rel.address_id
-> Merge Join (cost=0.00..5438.34 rows=22970 width=22)
Merge Cond: ("outer".id = "inner".addressline_id)
-> Index Scan using addressline_id_idx on addressline det (cost=0.00..2773.61 rows=22969 width=18)
Filter: ((detailname)::text = 'Npi'::text)
-> Index Scan using rel_address_has_addressline_idx2 on rel_address_has_addressline rel (cost=0.00..2082.13 rows=1181
93 width=8)
-> Sort (cost=7225.98..7286.76 rows=24310 width=22)
Sort Key: rel.address_id
-> Merge Join (cost=0.00..5455.09 rows=24310 width=22)
Merge Cond: ("outer".id = "inner".addressline_id)
-> Index Scan using addressline_id_idx on addressline det (cost=0.00..2773.61 rows=24309 width=18)
Filter: ((detailname)::text = 'Ton'::text)
-> Index Scan using rel_address_has_addressline_idx2 on rel_address_has_addressline rel (cost=0.00..2082.13 rows=118193 wid
th=8)
-> Sort (cost=7167.64..7226.84 rows=23679 width=22)
Sort Key: rel.address_id
-> Merge Join (cost=0.00..5447.20 rows=23679 width=22)
Merge Cond: ("outer".id = "inner".addressline_id)
-> Index Scan using addressline_id_idx on addressline det (cost=0.00..2773.61 rows=23678 width=18)
Filter: ((detailname)::text = 'Number'::text)
-> Index Scan using rel_address_has_addressline_idx2 on rel_address_has_addressline rel (cost=0.00..2082.13 rows=118193 width=8)
-> Sort (cost=7138.56..7196.97 rows=23364 width=22)
Sort Key: rel.address_id
-> Merge Join (cost=0.00..5443.27 rows=23364 width=22)
Merge Cond: ("outer".id = "inner".addressline_id)
-> Index Scan using addressline_id_idx on addressline det (cost=0.00..2773.61 rows=23363 width=18)
Filter: ((detailname)::text = 'Prefix'::text)
-> Index Scan using rel_address_has_addressline_idx2 on rel_address_has_addressline rel (cost=0.00..2082.13 rows=118193 width=8)
-> Sort (cost=7167.64..7226.84 rows=23679 width=22)
Sort Key: rel.address_id
-> Merge Join (cost=0.00..5447.20 rows=23679 width=22)
Merge Cond: ("outer".id = "inner".addressline_id)
-> Index Scan using addressline_id_idx on addressline det (cost=0.00..2773.61 rows=23678 width=18)
Filter: ((detailname)::text = 'AddrValue'::text)
-> Index Scan using rel_address_has_addressline_idx2 on rel_address_has_addressline rel (cost=0.00..2082.13 rows=118193 width=8)
-> Sort (cost=668.91..669.16 rows=100 width=22)
Sort Key: rel.address_id
-> Nested Loop (cost=0.00..665.58 rows=100 width=22)
-> Index Scan using addressline_detail_idx on addressline det (cost=0.00..366.01 rows=99 width=18)
Index Cond: ((detailname)::text = 'Link'::text)
-> Index Scan using rel_address_has_addressline_idx2 on rel_address_has_addressline rel (cost=0.00..3.01 rows=1 width=8)
Index Cond: (rel.addressline_id = "outer".id)
-> Sort (cost=668.91..669.16 rows=100 width=22)
Sort Key: rel.address_id
-> Nested Loop (cost=0.00..665.58 rows=100 width=22)
-> Index Scan using addressline_detail_idx on addressline det (cost=0.00..366.01 rows=99 width=18)
Index Cond: ((detailname)::text = 'House'::text)
-> Index Scan using rel_address_has_addressline_idx2 on rel_address_has_addressline rel (cost=0.00..3.01 rows=1 width=8)
Index Cond: (rel.addressline_id = "outer".id)
-> Sort (cost=668.91..669.16 rows=100 width=22)
Sort Key: rel.address_id
-> Nested Loop (cost=0.00..665.58 rows=100 width=22)
-> Index Scan using addressline_detail_idx on addressline det (cost=0.00..366.01 rows=99 width=18)
Index Cond: ((detailname)::text = 'Street'::text)
-> Index Scan using rel_address_has_addressline_idx2 on rel_address_has_addressline rel (cost=0.00..3.01 rows=1 width=8)
Index Cond: (rel.addressline_id = "outer".id)
-> Sort (cost=668.91..669.16 rows=100 width=22)
Sort Key: rel.address_id
-> Nested Loop (cost=0.00..665.58 rows=100 width=22)
-> Index Scan using addressline_detail_idx on addressline det (cost=0.00..366.01 rows=99 width=18)
Index Cond: ((detailname)::text = 'Town'::text)
-> Index Scan using rel_address_has_addressline_idx2 on rel_address_has_addressline rel (cost=0.00..3.01 rows=1 width=8)
Index Cond: (rel.addressline_id = "outer".id)
-> Sort (cost=668.91..669.16 rows=100 width=22)
Sort Key: rel.address_id
-> Nested Loop (cost=0.00..665.58 rows=100 width=22)
-> Index Scan using addressline_detail_idx on addressline det (cost=0.00..366.01 rows=99 width=18)
Index Cond: ((detailname)::text = 'City'::text)
-> Index Scan using rel_address_has_addressline_idx2 on rel_address_has_addressline rel (cost=0.00..3.01 rows=1 width=8)
Index Cond: (rel.addressline_id = "outer".id)
-> Sort (cost=668.91..669.16 rows=100 width=22)
Sort Key: rel.address_id
-> Nested Loop (cost=0.00..665.58 rows=100 width=22)
-> Index Scan using addressline_detail_idx on addressline det (cost=0.00..366.01 rows=99 width=18)
Index Cond: ((detailname)::text = 'County'::text)
-> Index Scan using rel_address_has_addressline_idx2 on rel_address_has_addressline rel (cost=0.00..3.01 rows=1 width=8)
Index Cond: (rel.addressline_id = "outer".id)
-> Sort (cost=668.91..669.16 rows=100 width=22)
Sort Key: rel.address_id
-> Nested Loop (cost=0.00..665.58 rows=100 width=22)
-> Index Scan using addressline_detail_idx on addressline det (cost=0.00..366.01 rows=99 width=18)
Index Cond: ((detailname)::text = 'Postcode'::text)
-> Index Scan using rel_address_has_addressline_idx2 on rel_address_has_addressline rel (cost=0.00..3.01 rows=1 width=8)
Index Cond: (rel.addressline_id = "outer".id)
-> Sort (cost=668.91..669.16 rows=100 width=22)
Sort Key: rel.address_id
-> Nested Loop (cost=0.00..665.58 rows=100 width=22)
-> Index Scan using addressline_detail_idx on addressline det (cost=0.00..366.01 rows=99 width=18)
Index Cond: ((detailname)::text = 'State'::text)
-> Index Scan using rel_address_has_addressline_idx2 on rel_address_has_addressline rel (cost=0.00..3.01 rows=1 width=8)
Index Cond: (rel.addressline_id = "outer".id)
-> Sort (cost=668.91..669.16 rows=100 width=22)
Sort Key: rel.address_id
-> Nested Loop (cost=0.00..665.58 rows=100 width=22)
-> Index Scan using addressline_detail_idx on addressline det (cost=0.00..366.01 rows=99 width=18)
Index Cond: ((detailname)::text = 'Zipcode'::text)
-> Index Scan using rel_address_has_addressline_idx2 on rel_address_has_addressline rel (cost=0.00..3.01 rows=1 width=8)
Index Cond: (rel.addressline_id = "outer".id)
-> Sort (cost=668.91..669.16 rows=100 width=22)
Sort Key: rel.address_id
-> Nested Loop (cost=0.00..665.58 rows=100 width=22)
-> Index Scan using addressline_detail_idx on addressline det (cost=0.00..366.01 rows=99 width=18)
Index Cond: ((detailname)::text = 'Extension'::text)
-> Index Scan using rel_address_has_addressline_idx2 on rel_address_has_addressline rel (cost=0.00..3.01 rows=1 width=8)
Index Cond: (rel.addressline_id = "outer".id)
-> Sort (cost=8.83..8.83 rows=2 width=39)
Sort Key: rel_contact.address_id
-> Nested Loop (cost=0.00..8.82 rows=2 width=39)
-> Index Scan using contact_key on contact (cost=0.00..5.77 rows=1 width=35)
Index Cond: ((contactid)::text = 'test'::text)
Filter: (((startdate IS NULL) OR (('now'::text)::timestamp(6) with time zone >= (startdate)::timestamp with time zone)) AND ((enddate IS NULL) OR (('now'::text)::timestamp(6) with time zone < (enddate)::
timestamp with time zone)))
-> Index Scan using rel_contact_has_address_idx1 on rel_contact_has_address rel_contact (cost=0.00..3.02 rows=2 width=8)
Index Cond: ("outer".id = rel_contact.contact_id)
(147 rows)

As you can see, the PublicView is resulting in a huge nested loop, with an index scan of the contact only occurring at the end. I would have expected something more like:

(1) An index scan of the contact table to determine the correct contact
(2) An index scan of the address table using the rel_contact_has_address.address_id to obtain the (relatively small - max 16, and typically 2) addresses
(3) A number of joins - at the same level rather than looping - to obtain the detailnames for the new column names of the public view

As I said in my original email, these delays are after applying all the performance related enhancements (fsync off, increased backbuffers, sort memory etc) I have picked up from the archives and FAQ. The upload script was also modified to commit and vacuum analyze at different intervals without providing any significant improvement. top reports the CPU usage at 99% - so I believe its all looping of the above intermediate SELECTs that is causing the spiralling delays as the number of rows increases.

Again, any help would be very much appreciated!

Damien

In response to

Responses

Browse pgsql-performance by date

  From Date Subject
Next Message Jeff 2003-10-29 14:01:54 Re: Adding foreign key performance
Previous Message Christopher Kings-Lynne 2003-10-29 01:47:28 Re: Adding foreign key performance