Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1tsekv-0044Mz-OK for pgsql-performance@arkaria.postgresql.org; Thu, 13 Mar 2025 09:21:34 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1tseku-008fzq-7V for pgsql-performance@arkaria.postgresql.org; Thu, 13 Mar 2025 09:21:32 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1tsekt-008fwV-Rp for pgsql-performance@lists.postgresql.org; Thu, 13 Mar 2025 09:21:31 +0000 Received: from mail-ej1-x630.google.com ([2a00:1450:4864:20::630]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.96) (envelope-from ) id 1tsekr-002aUk-1o for pgsql-performance@postgresql.org; Thu, 13 Mar 2025 09:21:30 +0000 Received: by mail-ej1-x630.google.com with SMTP id a640c23a62f3a-ac2bfcd2a66so128384966b.0 for ; Thu, 13 Mar 2025 02:21:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cybertec.at; s=google; t=1741857688; x=1742462488; darn=postgresql.org; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:to:from:subject:message-id:from:to:cc:subject:date :message-id:reply-to; bh=aJBXwfGWKn38w9umN1yxXXRJgr2lWNy1MMlNRza/M/M=; b=ijYXeANOdob0y734ESH3JwcIGjEehsNIy6OlRPAH6lzgWLnqgIqPzaFPn9EnQlhzy6 Q+qJE3EYFyrWo1XaDW1eQSETGI6bNc75kj08AbuVPKh4O0JdXLvU0cyW9P4Ih7HSUPwb 5FnTSwXk/JqCUZso1cMwpAnFBjTEkh2ZcsLQwcf4a26zxdtnIfi0GheENSv/JYRGiide M8qFqS+L8y4QHcgDUZz6O6qTb/N3+x8NiHGb02fateIpqXWJFT1xzY+YYQDjFqxG8a51 CrJ8CJpWMVqLWE9YBRBxWfmizSNQWPInejMMhk79CrlcOQiI+7XMCxF8qX/6M6+Tm4JS cwuQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741857688; x=1742462488; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:to:from:subject:message-id:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=aJBXwfGWKn38w9umN1yxXXRJgr2lWNy1MMlNRza/M/M=; b=Kcpcr8H9tJo1Uj7LT0Lrmd4JDrvthLHzTe2AW2ZcB7ZptnMYhlbsJndTS2IwzmkCbx 1LDZIn9j6UejVKGKAWDd3agAERYzvxGkHkzZKfGmT0dW62PbGA4DDrnj7pkRjHYsQtKO 6nhFHS8v9kQImSrKPxk/ZC0GTZpSomP9ktv3N9Ij5QnMBIGyCqNv9K7BW9b/wrnZsha+ 5S/96UlMlDte/cYpjUQdmJoAqb+/IgE0nWe7et3iV/gUccUvYVbN5X9ohpjBYVCuqKGg 8xmIlmTAbPBrhq5147z1TgIx/xd8V5ajFJyU7dgkkA4SVAzwYtMKeKjcffF2pcnb3pwo S8eg== X-Forwarded-Encrypted: i=1; AJvYcCVZ/6h1+iPhF1lDBZMCisIWzhTbgFR+b+Hg3j+TqFn0dJnS5DXajmoxfWmmlloNDREwMZis58o5snBmKSW+2TnLVQ==@postgresql.org X-Gm-Message-State: AOJu0YwAXeKkPG/3tnBUHvmVcaqBKpKzTgpXpzCgeBL8JdoKhm7Xfuig eAIUVTRqyjKMSxzCMvZ/0ORaGutyJs0d7J6jNVky8YCZiI/fWt5J2wHmN92bEK4VRco9HSl54dH b+X4= X-Gm-Gg: ASbGnctaOgVxr2Liv1gO89s3p+NyVCGcwqH/ROH62UN6haVB9sQ7seamy9rMm9HmuTS eouvEvaWWZEz1pCNdfdxz1MfCqx76zvfKMqfMsktVJjoaIqNwlXwC6ilYQKawQmUddp3LtlCIqO 0WuZqWy1e/HcPlSR52kHtEmCezKuaDpDp43PuNsX2XB2MEwMnUkdNVkprJ0oi6EVarhcZrBNG15 ru3VbxWnfLKfWSvzjqwYPQOEgAlCLqsut59Fc4UQRgkxaq0cTqk8BgmekaxUj1vHSAs+oD4y2pO KY2oPejFCvRf6GYbraUxgfG2ZcDQZcKUHfHLtPP38Lkp74FlI89GiRsGs5xKQTlb X-Google-Smtp-Source: AGHT+IFzq7NWWcJLuvHRA9KiJ7lTCT4BImer6XyyPivYWyfG2Iwjm1udx1VIwApVfNi0zHsRDUJwow== X-Received: by 2002:a17:907:980a:b0:ac0:b05:f0c0 with SMTP id a640c23a62f3a-ac2b9db4067mr1603340666b.1.1741857688037; Thu, 13 Mar 2025 02:21:28 -0700 (PDT) Received: from localhost.localdomain ([88.116.133.170]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-ac3146aef5dsm57728066b.35.2025.03.13.02.21.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 13 Mar 2025 02:21:27 -0700 (PDT) Message-ID: <0942a47d7a89f1b181f7e306f8389d9717eb5fe0.camel@cybertec.at> Subject: Re: Bulk DML performance From: Laurenz Albe To: bill.poole@ymail.com, pgsql-performance@postgresql.org Date: Thu, 13 Mar 2025 10:21:26 +0100 In-Reply-To: <008701db93cd$2eb404d0$8c1c0e70$@ymail.com> References: <008701db93cd$2eb404d0$8c1c0e70$.ref@ymail.com> <008701db93cd$2eb404d0$8c1c0e70$@ymail.com> Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable User-Agent: Evolution 3.54.3 (3.54.3-1.fc41) MIME-Version: 1.0 List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On Thu, 2025-03-13 at 12:05 +0800, bill.poole@ymail.com wrote: > The following INSERT .. ON CONFLICT (=E2=80=A6) DO UPDATE statement inser= ts/updates > 3 million rows with only 9 bytes per row and takes about 8 seconds on fir= st > run (to insert the rows) and about 14 seconds on subsequent runs (to upda= te > the rows), I can confirm these times on my not so new laptop with local NVME. That's the time it takes if you have an index on the table and want to be crash safe. > but is only inserting 27 MB of data (3 million rows with 9 byte= s > per row); although after the first run, > SELECT pg_size_pretty(pg_total_relation_size('test')) reports the table s= ize > as 191 MB and after the second run reports the table size as 382 MB (addi= ng > another 191 MB). That is unavoidable, because PostgreSQL adds a new version for each row to = the table. To avoid that kind of bloat, you'd have to update in smaller batche= s and run VACUUM between those to free the "dead" row versions. > CREATE TABLE test ( > =C2=A0 id bigint PRIMARY KEY, > =C2=A0 text1 text > ); > =C2=A0 > INSERT INTO test (id, text1) > SELECT generate_series, 'x' > FROM generate_series(1, 3000000) > ON CONFLICT (id) DO UPDATE > SET text1 =3D 'x'; > =C2=A0 > If PostgreSQL is writing 191 MB on the first run and 382 MB on each subse= quent > run, then PostgreSQL is only writing about 28 MB/s. Although PostgreSQL i= s > also able to write about 4.5 GB in about 35 seconds (as stated above), wh= ich > is about 128 MB/s, so it seems the performance constraint depends on the > number of rows inserted more than the size of each row. It is the index maintenance that is killing you. Without the primary key, the first insert takes under 1.8 seconds here. But you need the primary key index if you want to use INSERT ... ON CONFLIC= T. The update has to do even more work, so it is slower. If you don't need crash safety, you could use UNLOGGED tables and be somewh= at faster (5.8 seconds for the initial INSERT here). Essentially, the moderate performance is the price you are paying for data integrity (crash safety) and consistency (primary key). > Furthermore, deleting the rows takes about 18 seconds to perform (about 4 > seconds longer than the time taken to update the rows): > =C2=A0 > DELETE FROM test > WHERE id in ( > =C2=A0 SELECT * FROM generate_series(1, 3000000) > ) Well, that is not a great statement. The following takes only 1.6 seconds here: DELETE FROM test WHERE id BETWEEN 1 AND 3000000; And if you want to delete all rows, TRUNCATE is very, very fast. > It seems like it should be possible to do better than this on modern > hardware, but I don=E2=80=99t have enough knowledge of the inner workings= of > PostgreSQL to know whether my instinct is correct on this, so I thought > I=E2=80=99d raise the question with the experts. With the table as it is you won't get better performance if you want the features that a relational database provides. To get better performance, the best I can think of is to parallelize loading the data until you saturate CPU, disk or hit internal contention in the database. Yours, Laurenz Albe