Re: [PERFORM] EXPLAIN (no ANALYZE) taking an hour for INSERT FROM SELECT

2015-03-16 Thread Gunnlaugur Thor Briem
On Mon, Mar 16, 2015 at 7:24 PM, Jim Nasby jim.na...@bluetreble.com wrote:

 The other thing you should consider is using TRUNCATE instead of an
 un-filtered DELETE. It will both be much faster to perform and won't leave
 any dead rows behind.


Yep, but it does take an ACCESS EXCLUSIVE lock. We want the old table
contents to be readable to other sessions while the new table contents are
being populated (which can take quite a while), hence we don't use TRUNCATE.

Best of both worlds is to just populate a new table, flip over to that when
it's ready, and drop the old one once nobody's referring to it anymore.
That way we don't pay the DELETE scan penalty and don't leave dead rows,
and also don't lock reads out while we repopulate.

Gulli


Re: [PERFORM] EXPLAIN (no ANALYZE) taking an hour for INSERT FROM SELECT

2015-03-11 Thread Gunnlaugur Thor Briem
On Sat, Mar 7, 2015 at 3:44 PM, Tomas Vondra tomas.von...@2ndquadrant.com
wrote:

 Another possibility is that this is part
 of some large batch, and autovacuum simply did not have change to do the
 work.


Yes, I think that's it: I've just realized that immediately prior to the
INSERT, in the same transaction, an unfiltered DELETE has been issued; i.e.
the whole table is being rewritten. Then the INSERT is issued ... with a
WHERE clause on non-existence in the (now empty) table.

In that case of course the WHERE clause is unnecessary, as it will always
evaluate as true (and we've locked the whole table for writes). Looks like
it is a lot worse than unnecessary, though, if it triggers this performance
snafu in EXPLAIN INSERT.

This seems very likely to be the explanation here. So our workaround will
be to simply omit the WHERE clause in those cases where the full DELETE has
been issued. (And then vacuum afterwards.)

(Even better, just make the new table not temporary, and have it replace
the former table altogether. But that's for later; requires some broader
changes in our application.)

I'll report back if I *do* see the problem come up again despite this
change.

Thanks all for your help figuring this out!

Best regards,

Gulli


Re: [PERFORM] EXPLAIN (no ANALYZE) taking an hour for INSERT FROM SELECT

2015-03-05 Thread Gunnlaugur Thor Briem
Hi, thanks for your follow-up questions.

- postgres version is 9.1.13
- the number of rows (in this latest instance) is 28,474,842
- I've clustered and vacuum-full-ed and analyzed this table frequently,
attempting to troubleshoot this. (Running vacuum full on the whole catalog
seems a little excessive, and unlikely to help.)
- no other processes are likely to be interfering; nothing other than
PostgreSQL runs on this machine (except for normal OS processes and New
Relic server monitoring service); concurrent activity in PostgreSQL is
low-level and unrelated, and this effect is observed systematically
whenever this kind of operation is performed on this table
- no override for this table; the system default_statistics_target is 100
(the default)
- yes, an ANALYZE is performed on the temp table after the COPY and before
the INSERT
- no index on the temp table (but I'm scanning the whole thing anyway).
There are indexes on f_foo as detailed in my original post, and I expect
the PK to make the WHERE NOT EXISTS filtering efficient (as it filters on
exactly all columns of the PK) ... but even if it didn't, I would expect
that to only slow down the actual insert execution, not the EXPLAIN.

Cheers,

Gulli


On Wed, Mar 4, 2015 at 8:10 PM, Marc Mamin m.ma...@intershop.de wrote:

  Hi,
 we are seeing cases of EXPLAIN INSERT INTO foo SELECT ... taking over an
 hour, with disk I/O utilization (percent of time device is busy) at 100%
 the whole time, although I/O bandwidth is not saturated. This is on
 PostgreSQL 9.1.13.
 What could cause this? Note that there is no ANALYZE. Is it possible that
 the SELECT is actually executed, in planning the INSERT?
 When executing the INSERT itself (not EXPLAIN) immediately afterwards,
 that logs a temporary file message, but the EXPLAIN invocation does not
 (though the disk I/O suggests that a large on-disk sort is occurring):
 LOG:  temporary file: path base/pgsql_tmp/pgsql_tmp6016.0, size
 744103936
 STATEMENT:  INSERT INTO f_foo SELECT
 [...]
 During that actual execution, there's a lower disk I/O utilization
 (though a higher MB/s rate).
 Charts of disk I/O utilization and rate are at
 http://postimg.org/image/628h6jmn3/ ... the solid 100% span is the
 EXPLAIN statement, ending at 6:13:30pm, followed by the INSERT statement
 ending at 6:32pm. Metrics are collected by New Relic; their definition of
 I/O utilization is at https://discuss.newrelic.com/t/disk-i-o-metrics/2900
 Here's the EXPLAIN statement:
 LOG:  duration: 3928778.823 ms  statement: EXPLAIN INSERT INTO f_foo
 SELECT
t_foo.fk_d1,
t_foo.fk_d2,
t_foo.fk_d3,
t_foo.fk_d4,
t_foo.fk_d5,
t_foo.fk_d6,
t_foo.value
 FROM t_foo
 WHERE NOT (EXISTS
  (SELECT *
   FROM f_foo
   WHERE f_foo.fk_d2 = t_foo.fk_d2
 AND f_foo.fk_d3 = t_foo.fk_d3
 AND f_foo.fk_d4 = t_foo.fk_d4
 AND f_foo.fk_d5 = t_foo.fk_d5
 AND f_foo.fk_d6 = t_foo.fk_d6
 AND f_foo.fk_d1 = t_foo.fk_d1))
 (where t_foo is a temp table previously populated using COPY, and the NOT
 EXISTS subquery refers to the same table we are inserting into)
 Here's the EXPLAIN output:
 Insert on f_foo  (cost=8098210.50..9354519.69 rows=1 width=16)
   -  Merge Anti Join  (cost=8098210.50..9354519.69 rows=1 width=16)
 Merge Cond: ((t_foo.fk_d2 = public.f_foo.fk_d2) AND
  (t_foo.fk_d3 = public.f_foo.fk_d3) AND
  (t_foo.fk_d4 = public.f_foo.fk_d4) AND
  (t_foo.fk_d5 = public.f_foo.fk_d5) AND
  (t_foo.fk_d6 = public.f_foo.fk_d6) AND
  (t_foo.fk_d1 = public.f_foo.fk_d1))
 -  Sort  (cost=3981372.25..4052850.70 rows=28591380 width=16)
   Sort Key: t_foo.fk_d2, t_foo.fk_d3, t_foo.fk_d4,
 t_foo.fk_d5,
 t_foo.fk_d6, t_foo.fk_d1
   -  Seq Scan on t_foo  (cost=0.00..440461.80 rows=28591380
   width=16)
 -  Sort  (cost=4116838.25..4188025.36 rows=28474842 width=12)
   Sort Key: public.f_foo.fk_d2, public.f_foo.fk_d3,
 public.f_foo.fk_d4, public.f_foo.fk_d5,
 public.f_foo.fk_d6, public.f_foo.fk_d1
   -  Seq Scan on f_foo  (cost=0.00..591199.42 rows=28474842
   width=12)
 The INSERT is indeed rather large (which is why we're issuing an EXPLAIN
 ahead of it to log the plan). So its long execution time is expected. But I
 want to understand why the EXPLAIN takes even longer.
 The table looks like this:
 \d f_foo
 Table public.f_foo
  Column |   Type   | Modifiers
 +--+---
  fk_d1  | smallint | not null
  fk_d2  | smallint | not null
  fk_d3  | smallint | not null
  fk_d4  | smallint | not null
  fk_d5  | smallint | not null
  fk_d6  | smallint | not null
  value  | integer  |
 Indexes:
 

[PERFORM] EXPLAIN (no ANALYZE) taking an hour for INSERT FROM SELECT

2015-03-04 Thread Gunnlaugur Thor Briem
Hi,

we are seeing cases of EXPLAIN INSERT INTO foo SELECT ... taking over an
hour, with disk I/O utilization (percent of time device is busy) at 100%
the whole time, although I/O bandwidth is not saturated. This is on
PostgreSQL 9.1.13.

What could cause this? Note that there is no ANALYZE. Is it possible that
the SELECT is actually executed, in planning the INSERT?

When executing the INSERT itself (not EXPLAIN) immediately afterwards, that
logs a temporary file message, but the EXPLAIN invocation does not
(though the disk I/O suggests that a large on-disk sort is occurring):

LOG:  temporary file: path base/pgsql_tmp/pgsql_tmp6016.0, size 744103936
STATEMENT:  INSERT INTO f_foo SELECT
[...]

During that actual execution, there's a lower disk I/O utilization (though
a higher MB/s rate).

Charts of disk I/O utilization and rate are at
http://postimg.org/image/628h6jmn3/ ... the solid 100% span is the EXPLAIN
statement, ending at 6:13:30pm, followed by the INSERT statement ending at
6:32pm. Metrics are collected by New Relic; their definition of I/O
utilization is at https://discuss.newrelic.com/t/disk-i-o-metrics/2900

Here's the EXPLAIN statement:

LOG:  duration: 3928778.823 ms  statement: EXPLAIN INSERT INTO f_foo SELECT
   t_foo.fk_d1,
   t_foo.fk_d2,
   t_foo.fk_d3,
   t_foo.fk_d4,
   t_foo.fk_d5,
   t_foo.fk_d6,
   t_foo.value
FROM t_foo
WHERE NOT (EXISTS
 (SELECT *
  FROM f_foo
  WHERE f_foo.fk_d2 = t_foo.fk_d2
AND f_foo.fk_d3 = t_foo.fk_d3
AND f_foo.fk_d4 = t_foo.fk_d4
AND f_foo.fk_d5 = t_foo.fk_d5
AND f_foo.fk_d6 = t_foo.fk_d6
AND f_foo.fk_d1 = t_foo.fk_d1))

(where t_foo is a temp table previously populated using COPY, and the NOT
EXISTS subquery refers to the same table we are inserting into)

Here's the EXPLAIN output:

Insert on f_foo  (cost=8098210.50..9354519.69 rows=1 width=16)
  -  Merge Anti Join  (cost=8098210.50..9354519.69 rows=1 width=16)
Merge Cond: ((t_foo.fk_d2 = public.f_foo.fk_d2) AND
 (t_foo.fk_d3 = public.f_foo.fk_d3) AND
 (t_foo.fk_d4 = public.f_foo.fk_d4) AND
 (t_foo.fk_d5 = public.f_foo.fk_d5) AND
 (t_foo.fk_d6 = public.f_foo.fk_d6) AND
 (t_foo.fk_d1 = public.f_foo.fk_d1))
-  Sort  (cost=3981372.25..4052850.70 rows=28591380 width=16)
  Sort Key: t_foo.fk_d2, t_foo.fk_d3, t_foo.fk_d4, t_foo.fk_d5,
t_foo.fk_d6, t_foo.fk_d1
  -  Seq Scan on t_foo  (cost=0.00..440461.80 rows=28591380
  width=16)
-  Sort  (cost=4116838.25..4188025.36 rows=28474842 width=12)
  Sort Key: public.f_foo.fk_d2, public.f_foo.fk_d3,
public.f_foo.fk_d4, public.f_foo.fk_d5,
public.f_foo.fk_d6, public.f_foo.fk_d1
  -  Seq Scan on f_foo  (cost=0.00..591199.42 rows=28474842
  width=12)

The INSERT is indeed rather large (which is why we're issuing an EXPLAIN
ahead of it to log the plan). So its long execution time is expected. But I
want to understand why the EXPLAIN takes even longer.

The table looks like this:

\d f_foo
Table public.f_foo
 Column |   Type   | Modifiers
+--+---
 fk_d1  | smallint | not null
 fk_d2  | smallint | not null
 fk_d3  | smallint | not null
 fk_d4  | smallint | not null
 fk_d5  | smallint | not null
 fk_d6  | smallint | not null
 value  | integer  |
Indexes:
f_foo_pkey PRIMARY KEY, btree (fk_d2, fk_d6, fk_d4, fk_d3, fk_d5,
fk_d1) CLUSTER
ix_f_foo_d4 btree (fk_d4)
ix_f_foo_d3 btree (fk_d3)
ix_f_foo_d5 btree (fk_d5)
ix_f_foo_d6 btree (fk_d6)
Foreign-key constraints:
f_foo_d2_fkey FOREIGN KEY (fk_d2) REFERENCES d2(id) DEFERRABLE
f_foo_d6_fkey FOREIGN KEY (fk_d6) REFERENCES d6(id) DEFERRABLE
f_foo_d5_fkey FOREIGN KEY (fk_d5) REFERENCES d5(id) DEFERRABLE
f_foo_d4_fkey FOREIGN KEY (fk_d4) REFERENCES d4(id) DEFERRABLE
f_foo_d3_fkey FOREIGN KEY (fk_d3) REFERENCES d3(id) DEFERRABLE

Conceivably relevant (though I don't know how): this database has a very
large number of table objects (1.3 million rows in pg_class). But other
EXPLAINs are not taking anywhere near this long in this DB; the heavy
EXPLAIN is only seen on INSERT into this and a couple of other tables with
tens of millions of rows.

Any ideas?

Thanks, best regards,

- Gulli