mirror of
https://github.com/postgres/postgres.git
synced 2025-07-27 12:41:57 +03:00
pg_overexplain: Additional EXPLAIN options for debugging.
There's a fair amount of information in the Plan and PlanState trees that isn't printed by any existing EXPLAIN option. This means that, when working on the planner, it's often necessary to rely on facilities such as debug_print_plan, which produce excessively voluminous output. Hence, use the new EXPLAIN extension facilities to implement EXPLAIN (DEBUG) and EXPLAIN (RANGE_TABLE) as extensions to the core EXPLAIN facility. A great deal more could be done here, and the specific choices about what to print and how are definitely arguable, but this is at least a starting point for discussion and a jumping-off point for possible future improvements. Reviewed-by: Sami Imseih <samimseih@gmail.com> Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us> Reviweed-by: Andrei Lepikhov <lepihov@gmail.com> (who didn't like it) Discussion: http://postgr.es/m/CA+TgmoZfvQUBWQ2P8iO30jywhfEAKyNzMZSR+uc2xr9PZBw6eQ@mail.gmail.com
This commit is contained in:
105
contrib/pg_overexplain/sql/pg_overexplain.sql
Normal file
105
contrib/pg_overexplain/sql/pg_overexplain.sql
Normal file
@ -0,0 +1,105 @@
|
||||
-- These tests display internal details that would not be stable under
|
||||
-- debug_parallel_query, so make sure that option is disabled.
|
||||
SET debug_parallel_query = off;
|
||||
|
||||
-- These options do not exist, so these queries should all fail.
|
||||
EXPLAIN (DEBUFF) SELECT 1;
|
||||
EXPLAIN (DEBUG) SELECT 1;
|
||||
EXPLAIN (RANGE_TABLE) SELECT 1;
|
||||
|
||||
-- Load the module that creates the options.
|
||||
LOAD 'pg_overexplain';
|
||||
|
||||
-- The first option still does not exist, but the others do.
|
||||
EXPLAIN (DEBUFF) SELECT 1;
|
||||
EXPLAIN (DEBUG) SELECT 1;
|
||||
EXPLAIN (RANGE_TABLE) SELECT 1;
|
||||
|
||||
-- Create a partitioned table.
|
||||
CREATE TABLE vegetables (id serial, name text, genus text)
|
||||
PARTITION BY LIST (genus);
|
||||
CREATE TABLE daucus PARTITION OF vegetables FOR VALUES IN ('daucus');
|
||||
CREATE TABLE brassica PARTITION OF vegetables FOR VALUES IN ('brassica');
|
||||
INSERT INTO vegetables (name, genus)
|
||||
VALUES ('carrot', 'daucus'), ('bok choy', 'brassica'),
|
||||
('brocooli', 'brassica'), ('cauliflower', 'brassica'),
|
||||
('cabbage', 'brassica'), ('kohlrabi', 'brassica'),
|
||||
('rutabaga', 'brassica'), ('turnip', 'brassica');
|
||||
VACUUM ANALYZE vegetables;
|
||||
|
||||
-- We filter relation OIDs out of the test output in order to avoid
|
||||
-- test instability. This is currently only needed for EXPLAIN (DEBUG), not
|
||||
-- EXPLAIN (RANGE_TABLE).
|
||||
CREATE FUNCTION explain_filter(text) RETURNS SETOF text
|
||||
LANGUAGE plpgsql AS
|
||||
$$
|
||||
DECLARE
|
||||
ln text;
|
||||
BEGIN
|
||||
FOR ln IN EXECUTE $1
|
||||
LOOP
|
||||
ln := regexp_replace(ln, 'Relation OIDs:( \m\d+\M)+',
|
||||
'Relation OIDs: NNN...', 'g');
|
||||
ln := regexp_replace(ln, '<Relation-OIDs>( ?\m\d+\M)+</Relation-OIDs>',
|
||||
'<Relation-OIDs>NNN...</Relation-OIDs>', 'g');
|
||||
RETURN NEXT ln;
|
||||
END LOOP;
|
||||
END;
|
||||
$$;
|
||||
|
||||
-- Test with both options together and an aggregate.
|
||||
SELECT explain_filter($$
|
||||
EXPLAIN (DEBUG, RANGE_TABLE, COSTS OFF)
|
||||
SELECT genus, array_agg(name ORDER BY name) FROM vegetables GROUP BY genus
|
||||
$$);
|
||||
|
||||
-- Test a different output format.
|
||||
SELECT explain_filter($$
|
||||
EXPLAIN (DEBUG, RANGE_TABLE, FORMAT XML, COSTS OFF)
|
||||
SELECT genus, array_agg(name ORDER BY name) FROM vegetables GROUP BY genus
|
||||
$$);
|
||||
|
||||
-- Test just the DEBUG option. Verify that it shows information about
|
||||
-- disabled nodes, parallel safety, and the parallelModeNeeded flag.
|
||||
SET enable_seqscan = false;
|
||||
SET debug_parallel_query = true;
|
||||
SELECT explain_filter($$
|
||||
EXPLAIN (DEBUG, COSTS OFF)
|
||||
SELECT genus, array_agg(name ORDER BY name) FROM vegetables GROUP BY genus
|
||||
$$);
|
||||
RESET debug_parallel_query;
|
||||
RESET enable_seqscan;
|
||||
|
||||
-- Test the DEBUG option with a non-SELECT query, and also verify that the
|
||||
-- hasReturning flag is shown.
|
||||
SELECT explain_filter($$
|
||||
EXPLAIN (DEBUG, COSTS OFF)
|
||||
INSERT INTO vegetables (name, genus)
|
||||
VALUES ('Brotero''s carrot', 'brassica') RETURNING id
|
||||
$$);
|
||||
|
||||
-- Create an index, and then attempt to force a nested loop with inner index
|
||||
-- scan so that we can see parameter-related information. Also, let's try
|
||||
-- actually running the query, but try to suppress potentially variable output.
|
||||
CREATE INDEX ON vegetables (id);
|
||||
ANALYZE vegetables;
|
||||
SET enable_hashjoin = false;
|
||||
SET enable_material = false;
|
||||
SET enable_mergejoin = false;
|
||||
SET enable_seqscan = false;
|
||||
SELECT explain_filter($$
|
||||
EXPLAIN (BUFFERS OFF, COSTS OFF, SUMMARY OFF, TIMING OFF, ANALYZE, DEBUG)
|
||||
SELECT * FROM vegetables v1, vegetables v2 WHERE v1.id = v2.id;
|
||||
$$);
|
||||
RESET enable_hashjoin;
|
||||
RESET enable_material;
|
||||
RESET enable_mergejoin;
|
||||
RESET enable_seqscan;
|
||||
|
||||
-- Test the RANGE_TABLE option with a case that allows partition pruning.
|
||||
EXPLAIN (RANGE_TABLE, COSTS OFF)
|
||||
SELECT * FROM vegetables WHERE genus = 'daucus';
|
||||
|
||||
-- Also test a case that involves a write.
|
||||
EXPLAIN (RANGE_TABLE, COSTS OFF)
|
||||
INSERT INTO vegetables (name, genus) VALUES ('broccoflower', 'brassica');
|
Reference in New Issue
Block a user