performance - 在 View 中封装 Postgres 查询使其非常慢

标签 performance postgresql view window-functions

我有一个在 Postgres 8.4 上运行大约 5 秒的查询。它从连接到其他一些表的 View 中选择数据,但也使用 lag() 窗口函数,即。

SELECT *, lag(column1) OVER (PARTITION BY key1 ORDER BY ...), lag(...)
FROM view1 v
JOIN othertables USING (...)
WHERE ...

为方便起见,我创建了一个新 View ,其中包含

SELECT *, lag(column1) OVER (PARTITION BY key1 ORDER BY ...), lag(...)
FROM view1 v

然后从中选择,像以前一样使用所有其他 JOIN 和过滤器。令我惊讶的是,这个查询并没有在 12 分钟内完成(我在那个时候停止了它)。显然 Postgres 选择了不同的执行计划。我怎么让它不那样做,即。使用与原始查询相同的计划?我原以为 View 不应该更改执行计划,但显然它确实如此。

编辑:此外,我发现即使我将第一个 View 的内容复制到第二个 View 中,它仍然不会返回。

编辑 2:好的,我已经充分简化了查询以发布计划。

使用 View (这不会在任何合理的时间内返回):

Subquery Scan sp  (cost=5415201.23..5892463.97 rows=88382 width=370)
  Filter: (((sp.ticker)::text ~~ 'Some Ticker'::text) AND (sp.price_date >= '2010-06-01'::date))
  ->  WindowAgg  (cost=5415201.23..5680347.20 rows=53029193 width=129)
        ->  Sort  (cost=5415201.23..5441715.83 rows=53029193 width=129)
              Sort Key: sp.stock_id, sp.price_date
              ->  Hash Join  (cost=847.87..1465139.61 rows=53029193 width=129)
                    Hash Cond: (sp.stock_id = s.stock_id)
                    ->  Seq Scan on stock_prices sp  (cost=0.00..1079829.20 rows=53029401 width=115)
                    ->  Hash  (cost=744.56..744.56 rows=29519 width=18)
                          ->  Seq Scan on stocks s  (cost=0.00..744.56 rows=29519 width=18)

将窗口函数从 View 中取出并放入查询本身(这会立即返回):

WindowAgg  (cost=34.91..34.95 rows=7 width=129)
  ->  Sort  (cost=34.91..34.92 rows=7 width=129)
        Sort Key: sp.stock_id, sp.price_date
        ->  Nested Loop  (cost=0.00..34.89 rows=7 width=129)
              ->  Index Scan using stocks_ticker_unique on stocks s  (cost=0.00..4.06 rows=1 width=18)
                    Index Cond: ((ticker)::text = 'Some Ticker'::text)
                    Filter: ((ticker)::text ~~ 'Some Ticker'::text)
              ->  Index Scan using stock_prices_id_date_idx on stock_prices sp  (cost=0.00..30.79 rows=14 width=115)
                    Index Cond: ((sp.stock_id = s.stock_id) AND (sp.price_date >= '2010-06-01'::date))

所以看起来在缓慢的情况下它试图首先将窗口函数应用于所有数据然后过滤它,这可能是问题所在。不过,我不知道为什么要这样做。

最佳答案

这两个计划之间的区别在于加入聚合。这可以防止使用嵌套循环计划。当您在 View 中使用聚合时,您将自己置于不利的境地。

例如,这几乎总是会导致对两个表进行合并或散列连接计划,然后进行前 n 排序:

select foo.*
from foo
join (select bar.* from bar group by bar.field) as bar on foo.field = bar.field
where ...
order by bar.field
limit 10;

关于performance - 在 View 中封装 Postgres 查询使其非常慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3527213/

相关文章:

mysql - MySQL 中的用户 ID 与用户名性能

ruby-on-rails - rails 3 : Caching *all* pages from a controller without manually adding them

mysql - 使用 MYSQL_ASSOC 而不是 MYSQL_BOTH 获取 mysql 数组是否会影响性能

objective-c - UIViewController 编程启动/替换

android - 使用 Gmail 应用程序中的 View 突出显示 TextView 中的单词?

C# Entity Framework 4 导航属性导致提交时性能下降

postgresql - 是否有可能在 postgreSQL 逻辑复制插件中获取当前的 64 位 transactionId(带有纪元)

postgresql - 为什么 POSTGRESQL 的 row_number() 窗口函数在 psycopg2 中不起作用,但在命令行或 pgadmin 中起作用?

php - PDO_PGSQL 驱动是否支持预处理语句?

php - 在 PHP 中显示和链接外键内容