如何调试 PostgreSQL 中常见的 table 表达式?
How to debug common table expressions in PostgreSQL?
我在查询中遇到问题,其中一个 CTE return 没有行。但这很难被注意到,并且调试了很长时间。
是否可以在不注释掉主查询的情况下在 Postgres 中输出所有 CTE?
create or replace function generate_grid(
poly geometry, step double precision)
returns setof geometry as
$$ */
with
initial as (select st_xmin(poly) x0, st_ymin(poly) y0),
...(another 3 CTE skipped here)...
grid as (select point from points where st_intersects(point, poly)),
centroid as (select st_centroid(poly) point from grid where (select count(*)=0 from grid))
select * from grid
union all
select * from centroid;
$$ language sql;
在示例中,CTE centroid
被增量添加到之前运行良好的函数中。它应该 return 行以防 grid
为空。错误(我已修复)是它没有,因为它是从空 CTE grid
中选择的。现在,当我描述问题时,它失败的原因很明显,但是当您编写并调试时,可能会发生各种各样的事情,例如混合几何 SRID、错误 SRID 等。
EXPLAIN ANALYZE 希望单独报告 CTE。
当我 运行 那个 (Postgresql 9.4) 单独显示 CTE 时,在结果部分它确实显示从 "CTE Scan on x" 返回的实际行数是 0。
explain analyze
with x as (select 1 where false),
y as (select 2 where true)
select * from x, y;
Returns:
Nested Loop (cost=0.02..0.07 rows=1 width=8) (actual time=0.002..0.002 rows=0 loops=1)
Output: x."?column?", y."?column?"
CTE x
-> Result (cost=0.00..0.01 rows=1 width=0) (actual time=0.000..0.000 rows=0 loops=1)
Output: 1
One-Time Filter: false
CTE y
-> Result (cost=0.00..0.01 rows=1 width=0) (never executed)
Output: 2
-> CTE Scan on x (cost=0.00..0.02 rows=1 width=4) (actual time=0.002..0.002 rows=0 loops=1)
Output: x."?column?"
-> CTE Scan on y (cost=0.00..0.02 rows=1 width=4) (never executed)
Output: y."?column?"
Planning time: 0.034 ms
Execution time: 0.018 ms
我不知道 explain 会一直显示这样的数据,我怀疑这取决于 Postgresql 如何决定优化查询,但这应该是一个很好的起点。
在 http://www.postgresql.org/docs/current/static/sql-explain.html
解释文档
CROSS JOIN
的问题是当派生表之一为空时它不会产生任何输出:
with x as (select 1 where false),
y as (select 2 where true)
select * from x, y;
你需要 OUTER CROSS JOIN
.
在SQL Server
有很棒的OUTER APPLY
:
with x(c) as (select 1 where 1=0),
y(d) as (select 2 where 1=1)
select *
FROM (values ('Base')) AS s(val) -- always one row
OUTER APPLY x
OUTER APPLY y;
您可以使用 LEFT JOIN LATERAL
模拟此行为,但它看起来有点 "ugly":
;WITH x(c) AS (SELECT 1 WHERE false),
y(d) AS (SELECT 2 WHERE true)
SELECT *
FROM (VALUES ('Base row')) AS s(val)
LEFT JOIN LATERAL (SELECT * FROM x) AS x(c) ON true
LEFT JOIN LATERAL (SELECT * FROM y) AS y(d) ON true;
输出:
╔═══════════╦═════════╦═══╗
║ val ║ c ║ d ║
╠═══════════╬═════════╬═══╣
║ Base row ║ (null) ║ 2 ║
╚═══════════╩═════════╩═══╝
或简单的 LEFT JOIN
在这种情况下:
;WITH x(c) AS (SELECT 1 WHERE false),
y(d) AS (SELECT 2 WHERE true)
SELECT *
FROM (VALUES ('Base row')) AS s(val)
LEFT JOIN x ON true
LEFT JOIN y ON true;
我在查询中遇到问题,其中一个 CTE return 没有行。但这很难被注意到,并且调试了很长时间。
是否可以在不注释掉主查询的情况下在 Postgres 中输出所有 CTE?
create or replace function generate_grid(
poly geometry, step double precision)
returns setof geometry as
$$ */
with
initial as (select st_xmin(poly) x0, st_ymin(poly) y0),
...(another 3 CTE skipped here)...
grid as (select point from points where st_intersects(point, poly)),
centroid as (select st_centroid(poly) point from grid where (select count(*)=0 from grid))
select * from grid
union all
select * from centroid;
$$ language sql;
在示例中,CTE centroid
被增量添加到之前运行良好的函数中。它应该 return 行以防 grid
为空。错误(我已修复)是它没有,因为它是从空 CTE grid
中选择的。现在,当我描述问题时,它失败的原因很明显,但是当您编写并调试时,可能会发生各种各样的事情,例如混合几何 SRID、错误 SRID 等。
EXPLAIN ANALYZE 希望单独报告 CTE。
当我 运行 那个 (Postgresql 9.4) 单独显示 CTE 时,在结果部分它确实显示从 "CTE Scan on x" 返回的实际行数是 0。
explain analyze
with x as (select 1 where false),
y as (select 2 where true)
select * from x, y;
Returns:
Nested Loop (cost=0.02..0.07 rows=1 width=8) (actual time=0.002..0.002 rows=0 loops=1)
Output: x."?column?", y."?column?"
CTE x
-> Result (cost=0.00..0.01 rows=1 width=0) (actual time=0.000..0.000 rows=0 loops=1)
Output: 1
One-Time Filter: false
CTE y
-> Result (cost=0.00..0.01 rows=1 width=0) (never executed)
Output: 2
-> CTE Scan on x (cost=0.00..0.02 rows=1 width=4) (actual time=0.002..0.002 rows=0 loops=1)
Output: x."?column?"
-> CTE Scan on y (cost=0.00..0.02 rows=1 width=4) (never executed)
Output: y."?column?"
Planning time: 0.034 ms
Execution time: 0.018 ms
我不知道 explain 会一直显示这样的数据,我怀疑这取决于 Postgresql 如何决定优化查询,但这应该是一个很好的起点。
在 http://www.postgresql.org/docs/current/static/sql-explain.html
解释文档CROSS JOIN
的问题是当派生表之一为空时它不会产生任何输出:
with x as (select 1 where false),
y as (select 2 where true)
select * from x, y;
你需要 OUTER CROSS JOIN
.
在SQL Server
有很棒的OUTER APPLY
:
with x(c) as (select 1 where 1=0),
y(d) as (select 2 where 1=1)
select *
FROM (values ('Base')) AS s(val) -- always one row
OUTER APPLY x
OUTER APPLY y;
您可以使用 LEFT JOIN LATERAL
模拟此行为,但它看起来有点 "ugly":
;WITH x(c) AS (SELECT 1 WHERE false),
y(d) AS (SELECT 2 WHERE true)
SELECT *
FROM (VALUES ('Base row')) AS s(val)
LEFT JOIN LATERAL (SELECT * FROM x) AS x(c) ON true
LEFT JOIN LATERAL (SELECT * FROM y) AS y(d) ON true;
输出:
╔═══════════╦═════════╦═══╗
║ val ║ c ║ d ║
╠═══════════╬═════════╬═══╣
║ Base row ║ (null) ║ 2 ║
╚═══════════╩═════════╩═══╝
或简单的 LEFT JOIN
在这种情况下:
;WITH x(c) AS (SELECT 1 WHERE false),
y(d) AS (SELECT 2 WHERE true)
SELECT *
FROM (VALUES ('Base row')) AS s(val)
LEFT JOIN x ON true
LEFT JOIN y ON true;