Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtp (Exim 4.84_2) (envelope-from ) id 1eYsrs-0002i1-IO for pgsql-performance@arkaria.postgresql.org; Tue, 09 Jan 2018 12:19:01 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.84_2) (envelope-from ) id 1eYsrq-0003zM-Er for pgsql-performance@arkaria.postgresql.org; Tue, 09 Jan 2018 12:18:58 +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.84_2) (envelope-from ) id 1eYsrq-0003zD-6R for pgsql-performance@lists.postgresql.org; Tue, 09 Jan 2018 12:18:58 +0000 Received: from forward5p.cmail.yandex.net ([77.88.31.20]) by magus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA384:256) (Exim 4.89) (envelope-from ) id 1eYsrk-0000io-GF for pgsql-performance@lists.postgresql.org; Tue, 09 Jan 2018 12:18:55 +0000 Received: from mxback6o.mail.yandex.net (mxback6o.mail.yandex.net [IPv6:2a02:6b8:0:1a2d::20]) by forward5p.cmail.yandex.net (Yandex) with ESMTP id 1C63820EEC; Tue, 9 Jan 2018 15:18:50 +0300 (MSK) Received: from web47j.yandex.ru (web47j.yandex.ru [2a02:6b8:0:1619::347]) by mxback6o.mail.yandex.net (nwsmtp/Yandex) with ESMTP id W6gyVrJ0Y8-Ims4Zimu; Tue, 09 Jan 2018 15:18:48 +0300 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yandex.com; s=mail; t=1515500328; bh=XpHZp12sFB0HNB3hHB+awZFxnhjgYr4HGXyDYI7C2kg=; h=From:To:References:Subject:Message-Id:Date; b=wd2onDsm15dlYpNSguriGu39YvKVdmMi3eE/YEyh/u29RET9D5uCE6TsbX9yR1/Fw 1y8zHIesTy5OQ9HYUAWBWvfGqgGFONPXBMIe49t5rbQgXX4gkkc7FnbRCphDICAegR REtToCgXe6xmO61YeJL92urFhu6b4aSUxHBVcNtA= Authentication-Results: mxback6o.mail.yandex.net; dkim=pass header.i=@yandex.com Received: by web47j.yandex.ru with HTTP; Tue, 09 Jan 2018 15:18:48 +0300 From: Timokhin Maxim Envelope-From: ncx2@yandex.ru To: Tomas Vondra , "pgsql-performance@lists.postgresql.org" References: <145941513961163@web46o.yandex.ru> <59776cbc-bd4a-7ce9-133c-be5665075429@2ndquadrant.com> Subject: Re: Updating a large table MIME-Version: 1.0 Message-Id: <4917721515500328@web47j.yandex.ru> X-Mailer: Yamail [ http://yandex.ru ] 5.0 Date: Tue, 09 Jan 2018 15:18:48 +0300 Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset=utf-8 List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk Hello Tomas! Thank you for the useful answer! 23.12.2017, 23:58, "Tomas Vondra" : > On 12/22/2017 05:46 PM, Timokhin Maxim wrote: >>  Hello! We have a large table 11GB ( about 37 million records ) and we >>  need to alter a table - add a new column with default values is >>  false. Also 'NOT NULL' is required. >> >>  So, first I've done: >> >>  ALTER TABLE clusters ALTER COLUMN "is_paid"; > > That seems somewhat incomplete ... what exactly did the ALTER do? I'll try to explain what exactly I meant. ALTER TABLE clusters ADD COLUMN "is_paid" BOOLEAN NOT NULL DEFAULT FALSE; What exactly I need. But that query would lock the whole table for about 40 minutes. I decided to separate it like: 1. ALTER TABLE clusters ADD COLUMN "is_paid" BOOLEAN DEFAULT FALSE; 2. UPDATE clusters SET is_paid = DEFAULT where ctime <= now() - interval '720h' AND is_paid != FALSE; ( This was needed as soon as possible ) 3. UPDATE another part by chunks 4. set NOT NULL for the table. I was thinking about how to optimize the 3th step. Well, my solution was to write a script which runs two threads. The first one UPDATE "is_paid" by chunks, another one checks my metrics. If something is becoming wrong first thread stops until metrics are good. Thank you, Tomas. > >>  after that: >> >>  UPDATE clusters SET is_paid = DEFAULT where ctime <= now() - interval '720h' AND is_paid != FALSE; >> >>  Everything went ok. Then I tried to run it again for an interval of 1 >>  years. And I got that no one can't see - the was no available space >>  on a disk. The reason was WAL-files ate everything. >>  Master-server couldn't send some WAL-file to their replicas. Bandwidth wasn't enough. > > Well, then perhaps the best solution is to add more disk space and/or > make sure the network bandwidth is sufficient? > > In any case, don't forget this may also need to update all indexes on > the table, because the new row versions will end up on different pages. > So while the table has 11GB, this update may need much more WAL space > than that. > Got it, thank you! >>  Well, I'm searching for a better idea to update the table. >>  Solutions I found. >>  1. Separate my UPDATE by chunks. > > If this is a one-time change, this is probably the best option. > Exactly, thank you! >>  2. Alter a table using a new temporary table, but it's not convenient >>  for me because there is a lot of foreign keys and indexes. > > Right. > >>  3. Hot-update. This is the most interesting case for me. >>  Speaking of HOT-update https://www.dbrnd.com/2016/03/postgresql-the-awesome-table-fillfactor-to-speedup-update-and-select-statement/ >>  The article says: it might be useful for tables that change often and moreover It would be the best way to increase the speed of UPDATE. > > First of all, to make HOT possible there would have to be enough free > space on the pages. As you need to update the whole table, that means > each table would have to be only 50% full. That's unlikely to be true, > and you can't fix that at this point. > >>  So, my questions are will it work for all tuples? It says that - no >>  https://www.dbrnd.com/2016/03/postgresql-alter-table-to-change- >>  fillfactor-value/, but I could not find a confirmation in official >>  postresql's documentation. > > Not sure I understand your question, but HOT can only happen when two > conditions are met: > > 1) the update does not change any indexed column > > This is likely met, assuming you don't have an index on is_paid. > > 2) there's enough space on the same page for the new row version > > This is unlikely to be true, because the default fillfactor for tables > is 90%. You may change fillfactor using ALTER TABLE, but that only > applies to new data. > > Moreover, as the article says - this is useful for tables that change > often. Which is not quite what one-time table rewrite does. > > So HOT is not the solution you're looking for. > >>  Why do I need to launch vacuum after updating? > > You don't need to launch vacuum - autovacuum will take care of that > eventually. But you may do that, to do the cleanup when it's convenient > for you. > >>  How should I reduce the better fillfactor? > > For example to change fillfactor to 75% (i.e. 25% free space): > > ALTER TABLE t SET (fillfactor = 75); > > But as I said, it's not a solution for you. > >>  What will be with WAL-files it this case? > > Not sure what you mean. > > regards > > -- > Tomas Vondra http://www.2ndQuadrant.com > PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services