繁体   English   中英

如何调试PostgreSQL中的公用表表达式?

[英]How to debug common table expressions in PostgreSQL?

我在查询中遇到问题,其中一个CTE没有返回任何行。 但这很难注意到,调试还有很长一段时间。

是否可以输出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被逐渐添加到之前运行良好的函数中。 如果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;

返回:

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

我不知道解释会一直显示这样的数据,我怀疑它取决于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;

LiveDemo

您可以使用LEFT JOIN LATERAL模拟此行为,但它看起来有点“难看”:

;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;

SqlFiddleDemo

输出:

╔═══════════╦═════════╦═══╗
║   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;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM