Received: from localhost (maia-2.hub.org [200.46.204.187]) by postgresql.org (Postfix) with ESMTP id 8DCD69FB94C for ; Wed, 18 Jul 2007 08:05:39 -0300 (ADT) Received: from postgresql.org ([200.46.204.71]) by localhost (mx1.hub.org [200.46.204.187]) (amavisd-maia, port 10024) with ESMTP id 61360-05 for ; Wed, 18 Jul 2007 08:05:29 -0300 (ADT) X-Greylist: from auto-whitelisted by SQLgrey-1.7.5 Received: from h07.llord.com (unknown [195.140.142.194]) by postgresql.org (Postfix) with ESMTP id EDD2A9FA3A8 for ; Wed, 18 Jul 2007 08:05:32 -0300 (ADT) Received: from par69-8-88-161-102-87.fbx.proxad.net ([88.161.102.87] helo=apollo13) by h07.llord.com with esmtpa (Exim 4.66) (envelope-from ) id 1IB7LS-0006Ms-6G; Wed, 18 Jul 2007 13:05:26 +0200 Date: Wed, 18 Jul 2007 13:07:18 +0200 To: "Thomas Finneid" , pgsql-performance@postgresql.org Subject: Re: insert vs select into performance From: PFC Content-Type: text/plain; format=flowed; delsp=yes; charset=utf-8 MIME-Version: 1.0 References: <469D1AD3.9030004@ifi.uio.no> <469D342B.7080103@ifi.uio.no> Content-Transfer-Encoding: 8bit Message-ID: In-Reply-To: <469D342B.7080103@ifi.uio.no> User-Agent: Opera Mail/9.21 (Linux) X-PopBeforeSMTPSenders: junk@peufeu.com, lists@peufeu.com, peufeu@peufeu.com, pfcaillaud@peufeu.com X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - h07.llord.com X-AntiAbuse: Original Domain - postgresql.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - peufeu.com X-Source: X-Source-Args: X-Source-Dir: X-Virus-Scanned: Maia Mailguard 1.0.1 X-Spam-Status: No, hits=1.633 tagged_above=0 required=5 tests=AWL=0.571, BAYES_05=-1.11, RCVD_IN_NJABL_SPAM=2.072, RDNS_NONE=0.1 X-Spam-Level: * X-Archive-Number: 200707/209 X-Sequence-Number: 25893 >> It's the time to parse statements, plan, execute, roundtrips with >> the client, context switches, time for your client library to escape >> the data and encode it and for postgres to decode it, etc. In a word : >> OVERHEAD. > > I know there is some overhead, but that much when running it batched...? Well, yeah ;) > Unfortunately its not fast enough, it needs to be done in no more than > 1-2 seconds, ( and in production it will be maybe 20-50 columns of data, > perhaps divided over 5-10 tables.) > Additionally it needs to scale to perhaps three times as many columns > and perhaps 2 - 3 times as many rows in some situation within 1 seconds. > Further on it needs to allow for about 20 - 50 clients reading much of > that data before the next batch of data arrives. Wow. What is the application ? Test run on a desktop PC, Athlon 64 3200+, 2 IDE disks in RAID1 (pretty slow) : test=> CREATE TABLE test (a INT, b INT, c INT, d INT, e INT, f INT); CREATE TABLE Temps : 11,463 ms test=> INSERT INTO test SELECT 1,2,3,4,5,a FROM generate_series( 1, 100000 ) as a; INSERT 0 100000 Temps : 721,579 ms OK, so you see, insert speed is pretty fast. With a better CPU and faster disks, you can get a lot more. test=> TRUNCATE TABLE test; TRUNCATE TABLE Temps : 30,010 ms test=> ALTER TABLE test ADD PRIMARY KEY (f); INFO: ALTER TABLE / ADD PRIMARY KEY créera un index implicite «test_pkey» pour la table «test» ALTER TABLE Temps : 100,577 ms test=> INSERT INTO test SELECT 1,2,3,4,5,a FROM generate_series( 1, 100000 ) as a; INSERT 0 100000 Temps : 1915,928 ms This includes the time to update the index. test=> DROP TABLE test; DROP TABLE Temps : 28,804 ms test=> CREATE TABLE test (a INT, b INT, c INT, d INT, e INT, f INT); CREATE TABLE Temps : 1,626 ms test=> CREATE OR REPLACE FUNCTION test_insert( ) RETURNS VOID LANGUAGE plpgsql AS $$ DECLARE _i INTEGER; BEGIN FOR _i IN 0..100000 LOOP INSERT INTO test (a,b,c,d,e,f) VALUES (1,2,3,4,5, _i); END LOOP; END; $$; CREATE FUNCTION Temps : 51,948 ms test=> SELECT test_insert(); test_insert ------------- (1 ligne) Temps : 1885,382 ms Now you see, performing 100K individual inserts inside a plpgsql function is also fast. The postgres engine is pretty damn fast ; it's the communication overhead that you feel, especially switching between client and server processes. Another example : => INSERT INTO test (a,b,c,d,e,f) VALUES (... 100000 integer tuples) INSERT 0 100000 Temps : 1836,458 ms VALUES is actually pretty fast. Here, there is no context switch, everything is done in 1 INSERT. However COPY is much faster because the parsing overhead and de-escaping of data is faster. COPY is optimized for throughput. So, advice : For optimum throughput, have your application build chunks of data into text files and use COPY. Or if your client lib supports the copy interface, use it. You will need a fast disk system with xlog and data on separate disks, several CPU cores (1 insert thread will max out 1 core, use the others for selects), lots of RAM so index updates don't need to seek, and tuning of bgwriter and checkpoints to avoid load spikes.