使用LIMIT 0查询性能

时间:2017-10-19 15:10:32

标签: python postgresql

我的应用程序将接收用户提交的选择查询,但不是执行它并获得完整的结果集,在这个阶段,它只需要列名和&类型。

用户将是数据分析师,因此我希望提交大量冗长的查询。随着数据量的增长,提交的查询将在应用程序中保留并经常评估(基于触发器和crons的混合)。

客户端应用程序是用python& sqlalchemy-core与数据库进行交互。

目前我在查询结尾追加LIMIT 0以获取结果元数据。到目前为止,这给了我可接受的结果

示例:

查询待检查:

SELECT * FROM users

探究查询

SELECT * FROM users LIMIT 0

EXPLAIN ANALYZE会返回以下结果:

Limit  (cost=0.00..0.11 rows=1 width=646) (actual time=0.001..0.001 rows=0 loops=1)
  ->  Seq Scan on users  (cost=0.00..22457.28 rows=207728 width=646) (never executed)
Planning time: 0.067 ms
Execution time: 0.025 ms

请注意Seq Scan on users有一个注释(never executed)

接下来,我在一个更复杂的查询上尝试LIMIT 0,结果如下:

EXPLAIN ANALYZE
WITH blah AS (
SELECT * 
FROM users 
JOIN reservation 
  ON reservation.user_id = users.id
)
SELECT * FROM blah 
LIMIT 0

-- result:
Limit  (cost=482925.94..482925.96 rows=1 width=1955) (actual time=0.001..0.001 rows=0 loops=1)
  CTE blah
    ->  Hash Join  (cost=42094.88..482925.94 rows=1563750 width=1418) (never executed)
          Hash Cond: (reservation.user_id = users.id)
          ->  Seq Scan on reservation  (cost=0.00..96868.50 rows=1563750 width=772) (never executed)
          ->  Hash  (cost=22457.28..22457.28 rows=207728 width=646) (never executed)
                ->  Seq Scan on users  (cost=0.00..22457.28 rows=207728 width=646) (never executed)
  ->  CTE Scan on blah  (cost=0.00..31275.00 rows=1563750 width=1955) (never executed)
Planning time: 8.284 ms
Execution time: 0.113 ms

同样,所产生的唯一成本是计划时间和时间。更短的执行时间。

问题:

  1. 假设总时间的上限是规划时间的两倍是否安全?

  2. 在Postgresql中,我认为CTE一直都是优化围栏。但是,对于LIMIT 0,CTE似乎没有实现(never executed)。这是我可以依赖的行为(9.5 +)

  3. 是否有更简单/更有效的方法来获取选择查询的元数据? 如果我可以假设上述第1点,那么这不是一个非常重要的问题

  4. 传闻,您在SELECT查询中观察到的最大规划时间是什么?

  5. 我很确定即使数据量在基础表中增长,我也可以假设同一查询的计划时间相似。是否存在不适用的情况?

1 个答案:

答案 0 :(得分:1)

  1. 认为在大多数情况下执行时间大致保持不变,但数据修改CTE的情况除外(见下文)。

  2. 如果CTE永远不会被使用,则不会执行。此规则的例外情况是CTE中是否存在数据修改语句;在这种情况下,CTE始终执行。

  3. 我不认为PL / Python有更好的方法。如果你编写一个C函数,你可以准备语句,然后得到它的结果列,但它也可能是非平凡的。

  4. 没有很酷的故事要分享......

  5. 计划时间与表格的大小无关。