Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA384:256) (Exim 4.89) (envelope-from ) id 1erwP5-00047F-Ea for pgsql-performance@arkaria.postgresql.org; Sat, 03 Mar 2018 01:56:03 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1erwP4-0000Rb-4Y for pgsql-performance@arkaria.postgresql.org; Sat, 03 Mar 2018 01:56:02 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA384:256) (Exim 4.89) (envelope-from ) id 1erwP3-0000RS-Ss for pgsql-performance@lists.postgresql.org; Sat, 03 Mar 2018 01:56:01 +0000 Received: from mail-wr0-x22b.google.com ([2a00:1450:400c:c0c::22b]) by magus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1erwOz-0002ix-Tv for pgsql-performance@lists.postgresql.org; Sat, 03 Mar 2018 01:56:01 +0000 Received: by mail-wr0-x22b.google.com with SMTP id m12so11822841wrm.13 for ; Fri, 02 Mar 2018 17:55:57 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=2ndquadrant-com.20150623.gappssmtp.com; s=20150623; h=subject:to:references:from:organization:cc:message-id:date :user-agent:mime-version:in-reply-to:content-language :content-transfer-encoding; bh=FEsFOPiKKj5FS9KqYnNz/tEs7asoR+PlHV9iWfhCmAo=; b=bJcXumh8GjEBCKbzRz4mbxIe0mN5pUmSyFrLaSZSiHpAkizRipfI5pxp7GqBDMB3Ye TzOTm7i85u5U+litioQrC4iHXaBz8bV4IdDCyxwkHXeXuFB6bQcBjw63DuBhYLVm4XVd LgnFcegmSb5XyNkkWkN92f95fePh34QPtxUFUBqbBfKDJ9W8oMgNvQ9F3va5sdM+rPVF zRTJdrmRgcIcLFUGWY84u32ZAh6JHR9Ds8vaYNCZyIQwdcsEwAJG8YFcbLd+/k9/ZYan QWlFIRxkhuo6xRliofkzBEPRTjMTTzplOFkmI/akdfyAayaYA73jMJJmUS3jJV8LPQky 6BqQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:references:from:organization:cc :message-id:date:user-agent:mime-version:in-reply-to :content-language:content-transfer-encoding; bh=FEsFOPiKKj5FS9KqYnNz/tEs7asoR+PlHV9iWfhCmAo=; b=RddUGtQdTjo2KdrpJQKRYGFczRceocsdrBuDGj+0IWsYV6s7DOQQc9dwJbwt+MFmbO 3d+k25nNeisL6cgjpQaYijDEp3ZqvP/v9DTlqn1ksXDn+f2FWUgSOkGTGsQTJ8ghiIl2 hB4wCXBa1Gi4jofkW0sA3SnGUIXWWkHc5wy30kn7J8qdaRB/l/kjzo0SL8FjLtHxJVvK Dq7Oy/Im7f/3XneqcnojDPBqMUKShnaVP80+rdBgdh7HoWqFo/23fvaPSJGvhZW3TKEV fGP/+3kfDV3Cz8X+URbROWQqBb0iLSxUtfKOn29Pr7ppHJXEvzYirC8poP3wZ+rZp5ws EfNA== X-Gm-Message-State: APf1xPAGtmPEfW6kw5XgUZ5LouwvYW1rjubBCSwYHOD+MV5E84zSvTDh uzGwZz1O8Kgu05fre047hUnWH0DWOuI= X-Google-Smtp-Source: AG47ELsJtw+PqyZoj+F68VK9DOHt9S3sAlqDxI1pfPqDeghHuat+mdHYGH0oI7Tf/y6S+RD1VbX4NQ== X-Received: by 10.223.156.206 with SMTP id h14mr6037610wre.281.1520042155974; Fri, 02 Mar 2018 17:55:55 -0800 (PST) Received: from [10.8.8.53] ([185.94.189.189]) by smtp.gmail.com with ESMTPSA id s21sm6398715wra.45.2018.03.02.17.55.54 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 02 Mar 2018 17:55:55 -0800 (PST) Subject: Re: Updating large tables without dead tuples To: "ldh@laurent-hasson.com" , "pgsql-performance@lists.postgresql.org" References: From: Vik Fearing Organization: 2ndQuadrant France Cc: Stephen Frost Message-ID: Date: Sat, 3 Mar 2018 02:55:52 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.6.0 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=windows-1252 Content-Language: en-US Content-Transfer-Encoding: 8bit List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk On 02/24/2018 12:27 AM, ldh@laurent-hasson.com wrote: > Hello > >   > > I work with a large and wide table (about 300 million rows, about 50 > columns), and from time to time, we get business requirements to make > some modifications. But sometimes, it’s just some plain mistake. This > has happened to us a few weeks ago where someone made a mistake and we > had to update a single column of a large and wide table. Literally, the > source data screwed up a zip code and we had to patch on our end. > >   > > Anyways… Query ran was: > >     update T set source_id = substr(sourceId, 2, 10); > > Took about 10h and created 100’s of millions of dead tuples, causing > another couple of hours of vacuum. > >   > > This was done during a maintenance window, and that table is read-only > except when we ETL data to it on a weekly basis, and so I was just > wondering why I should pay the “bloat” penalty for this type of > transaction. Is there a trick that could be use here? Yes, there is a trick I like to use here, as long as you don't mind locking the table (even against reads). I'll assume T.source_id is of type text. If it's not, use whatever the actual type is. ALTER TABLE T ALTER COLUMN source_id TYPE text USING substr(sourceId, 2, 10); I copied what you had verbatim, I earnestly hope you don't have two columns source_id and sourceId in your table. This will rewrite the entire table just the same as a VACUUM FULL after your UPDATE would. Don't forget to VACUUM ANALYZE this table after the operation. Even though there will be no dead rows, you still need to VACUUM it to generate the visibility map and you need to ANALYZE it for statistics on your "new" column. Foreign keys remain intact with this solution and you don't have double wal logging like for an UPDATE. -- Vik Fearing +33 6 46 75 15 36 http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support