Received: from maia.hub.org (maia-2.hub.org [200.46.204.251]) by mail.postgresql.org (Postfix) with ESMTP id E7387B5DC6A for ; Tue, 12 Jul 2011 17:58:58 -0300 (ADT) Received: from mail.postgresql.org ([200.46.204.86]) by maia.hub.org (mx1.hub.org [200.46.204.251]) (amavisd-maia, port 10024) with ESMTP id 62834-09 for ; Tue, 12 Jul 2011 20:58:52 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from nm26.bullet.mail.sp2.yahoo.com (nm26.bullet.mail.sp2.yahoo.com [98.139.91.96]) by mail.postgresql.org (Postfix) with SMTP id BDE38B5DBF1 for ; Tue, 12 Jul 2011 17:58:51 -0300 (ADT) Received: from [98.139.91.64] by nm26.bullet.mail.sp2.yahoo.com with NNFMP; 12 Jul 2011 20:58:51 -0000 Received: from [208.71.42.197] by tm4.bullet.mail.sp2.yahoo.com with NNFMP; 12 Jul 2011 20:58:50 -0000 Received: from [127.0.0.1] by smtp208.mail.gq1.yahoo.com with NNFMP; 12 Jul 2011 20:58:50 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s1024; t=1310504330; bh=v3rZzLRG2iGpiistKELiQH0oojSvZathYsg5yl/xwJ8=; h=X-Yahoo-Newman-Id:Received:X-Yahoo-SMTP:X-YMail-OSG:X-Yahoo-Newman-Property:Message-ID:Date:From:User-Agent:MIME-Version:To:CC:Subject:References:In-Reply-To:Content-Type:Content-Transfer-Encoding; b=PUy4zW6DTZ/+f5MCKZDzO9RWXohS0jq9S9a3lbBUmQi7tzS/rPGFd/7ybcmOLWNStMp5U4qXwUuj/SRkpD8KjFov+mVXuxHIxiLGG8c5/RydKnUKuWUY78O5PT8+YzkJa7fdIpWsZqvGNzxV7+OulQ8gw2Ya4eNLT2iNAqw43/o= X-Yahoo-Newman-Id: 882850.83253.bm@smtp208.mail.gq1.yahoo.com Received: from [192.168.206.5] (lhofhansl@67.170.234.149 with plain) by smtp208.mail.gq1.yahoo.com with SMTP; 12 Jul 2011 13:58:50 -0700 PDT X-Yahoo-SMTP: YmezqLWswBDx0ai534H100MJuqGzDQ-- X-YMail-OSG: mPs93fYVM1m3ZyezjuWFMgws2OGpt2.Q6BjQbsYD7upNimS vrIeoLN4wLacGLNHftyfdMCI5aCV42piESCDfjMk8pzVnKt7wlwrKn1azM3Q roVjYM3ko7ZGktNKvFqMQ1dx0aNCoFzoDYH.S_BX7uUE.1MItUM.0ZFxjBZ. DpPpXzxzR26Yky1MoRa6hg72v.ooikg_ukD3dYFVlYNuv5n8fRAG4FqaL.iL .D6pFQyy6eBMec59nL.nsT38EmDiH2GZ5h5i_PYF3cnRfroPI760rG1OeTwj VtLMlj.4BEBNHnKpiEKvUukfCSwNg0GS0Tgo_z5CAsYmd99yVoQHosI9oOYH ITuso9k4TeeOBGMWkQ7StbS8dulrC1DwfHU0feqkDrH_R.0NzFsB7sULV4S6 ly5.W0ORLvfjco63Mnf3_iMIH7ia0k9mEUv0jPAJi_Hinm2ygrrEDftr4pSi sIYnnGFjUwX49UafICivl14rQ X-Yahoo-Newman-Property: ymail-3 Message-ID: <4E1CB56E.7080801@yahoo.com> Date: Tue, 12 Jul 2011 13:58:22 -0700 From: lars User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.18) Gecko/20110621 Fedora/3.1.11-1.fc14 Thunderbird/3.1.11 MIME-Version: 1.0 To: Kevin Grittner CC: Ivan Voras , pgsql-performance@postgresql.org Subject: Re: UPDATEDs slowing SELECTs in a fully cached database References: <4E16479D.3050605@yahoo.com> <4E1A0CBC.6090009@yahoo.com> <4E1A31AB.9010201@postnewspapers.com.au> <1310359653.80687.YahooMailRC@web121705.mail.ne1.yahoo.com> <4E1AEDAB020000250003F1C3@gw.wicourts.gov> <4E1B41EA.90104@yahoo.com> <4E1B05CC020000250003F1E6@gw.wicourts.gov> <4E1B810D.4070404@yahoo.com> <4E1B90AF.1020408@yahoo.com> <4E1C9A05.7060005@yahoo.com> <4E1C5563020000250003F252@gw.wicourts.gov> <4E1CA8E9.6090108@yahoo.com> In-Reply-To: <4E1CA8E9.6090108@yahoo.com> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Virus-Scanned: Maia Mailguard 1.0.1 X-Spam-Status: No, hits=-1.909 tagged_above=-10 required=5 tests=BAYES_00=-1.9, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, T_RP_MATCHES_RCVD=-0.01 X-Spam-Level: X-Archive-Number: 201107/121 X-Sequence-Number: 44333 On 07/12/2011 01:04 PM, lars wrote: > On 07/12/2011 12:08 PM, Kevin Grittner wrote: >> lars wrote: >> >>> select count(*) from test where tenant = $1 and created_date = $2 >> >> Ah, that might be a major clue -- prepared statements. >> >> What sort of a plan do you get for that as a prepared statement? >> (Note, it is very likely *not* to be the same plan as you get if you >> run with literal values!) It is not at all unlikely that it could >> resort to a table scan if you have one tenant which is five or ten >> percent of the table, which would likely trigger the pruning as it >> passed over the modified pages. >> >> -Kevin > So a read of a row *will* trigger dead tuple pruning, and that > requires WAL logging, and this is known/expected? > This is actually the only answer I am looking for. :) I have not seen > this documented anywhere. > > I know that Postgres will generate general plans for prepared > statements (how could it do otherwise?), > I also know that it sometimes chooses a sequential scan. > This can always be tweaked to touch fewer rows and/or use a different > plan. That's not my objective, though! > > The fact that a select (maybe a big analytical query we'll run) > touching many rows will update the WAL and wait > (apparently) for that IO to complete is making a fully cached database > far less useful. > I just artificially created this scenario. > > ... Just dropped the table to test something so I can't get the plan > right now. Will send an update as soon as I get > it setup again. > > Thanks again. > > -- Lars > > Ok... Slightly changes the indexes: \d test Table "lars.test" Column | Type | Modifiers --------------+---------------+----------- tenant | character(15) | created_by | character(15) | created_date | date | Indexes: "i1" btree (tenant) So just just a simple index on tenant. prepare x as select count(*) from test where tenant = $1 and created_date = $2; PREPARE explain execute x('000000000000001','2011-6-30'); QUERY PLAN ------------------------------------------------------------------------------- Aggregate (cost=263301.40..263301.41 rows=1 width=0) -> Bitmap Heap Scan on test (cost=3895.99..263299.28 rows=847 width=0) Recheck Cond: (tenant = $1) Filter: (created_date = $2) -> Bitmap Index Scan on i1 (cost=0.00..3895.77 rows=169372 width=0) Index Cond: (tenant = $1) (6 rows) -- this is when the WAL rows are written: explain (analyze on, buffers on) execute x('000000000000001','2011-6-30'); QUERY PLAN ---------------------------------------------------------------------------------------------------------------------------- Aggregate (cost=263301.40..263301.41 rows=1 width=0) (actual time=191.150..191.151 rows=1 loops=1) Buffers: shared hit=3716 -> Bitmap Heap Scan on test (cost=3895.99..263299.28 rows=847 width=0) (actual time=1.966..188.221 rows=3712 loops=1) Recheck Cond: (tenant = $1) Filter: (created_date = $2) Buffers: shared hit=3716 -> Bitmap Index Scan on i1 (cost=0.00..3895.77 rows=169372 width=0) (actual time=1.265..1.265 rows=3712 loops=1) Index Cond: (tenant = $1) Buffers: shared hit=20 Total runtime: 191.243 ms (10 rows) -- this is when no WAL is written: explain (analyze on, buffers on) execute x('000000000000001','2011-6-30'); QUERY PLAN ---------------------------------------------------------------------------------------------------------------------------- Aggregate (cost=263301.40..263301.41 rows=1 width=0) (actual time=11.529..11.530 rows=1 loops=1) Buffers: shared hit=3715 -> Bitmap Heap Scan on test (cost=3895.99..263299.28 rows=847 width=0) (actual time=1.341..9.187 rows=3712 loops=1) Recheck Cond: (tenant = $1) Filter: (created_date = $2) Buffers: shared hit=3715 -> Bitmap Index Scan on i1 (cost=0.00..3895.77 rows=169372 width=0) (actual time=0.756..0.756 rows=3712 loops=1) Index Cond: (tenant = $1) Buffers: shared hit=19 Total runtime: 11.580 ms (10 rows) If you wanted to recreate this scenario I created a simple script to create the table: create table test(tenant char(15), created_by char(15), created_date date); insert into test values('x', 'y','2011-6-30'); insert into test select * from test; insert into test select * from test; insert into test select * from test; insert into test select * from test; insert into test select * from test; insert into test select * from test; insert into test select * from test; insert into test select * from test; insert into test select * from test; insert into test select * from test; insert into test select * from test; insert into test select * from test; insert into test select * from test; insert into test select * from test; insert into test select * from test; insert into test select * from test; insert into test select * from test; insert into test select * from test; -- 256k rows update test set tenant = lpad((random()*10000)::int::text,15,'0'), created_by = lpad((random()*10000)::int::text,15,'0'); insert into test select * from test; insert into test select * from test; insert into test select * from test; insert into test select * from test; insert into test select * from test; insert into test select * from test; insert into test select * from test; -- 32m rows create index i1 on test(tenant); vacuum analyze; I use JDBC to perform the updates and selects, but this will do too: prepare x as select count(*) from test where tenant = $1 and created_date = $2; prepare y as update test set created_by = $1 where tenant = $2 and created_date = $3; execute y('000000000000001', '000000000000001','2011-6-30'); execute x('000000000000001','2011-6-30'); I'll probably compile Postgres with WAL debug on next, and try the page inspect module. On the face of it, though, this looks like Postgres would not be that useful as database that resides (mostly) in the cache. Here what the query mentioned here returns (note that shared_buffers is very large, but I observed the same with smaller settings): http://wiki.postgresql.org/wiki/Server_Configuration name | current_setting ------------------------------+------------------------------------------------------------------------------------------------------------------ version | PostgreSQL 9.1beta2 on x86_64-unknown-linux-gnu, compiled by gcc (GCC) 4.4.4 20100726 (Red Hat 4.4.4-13), 64-bit autovacuum | off bgwriter_delay | 10ms bgwriter_lru_maxpages | 1000 checkpoint_completion_target | 0.9 checkpoint_segments | 128 client_encoding | UTF8 effective_cache_size | 64GB lc_collate | en_US.UTF-8 lc_ctype | en_US.UTF-8 log_checkpoints | on log_line_prefix | %m maintenance_work_mem | 2GB max_connections | 100 max_stack_depth | 2MB server_encoding | UTF8 shared_buffers | 20GB TimeZone | UTC wal_buffers | 16MB work_mem | 1GB (20 rows) Thanks. -- Lars