postgres 查询性能:视图与函数

jdi*_*n04 7 postgresql performance postgresql-performance

我有一个场景,我需要运行工资报告。该报告计算特定日期范围内按员工分组的工资金额。

例如,当运行 2016-11-01 到 2016-11-30 的报告时,我会看到以下结果:

Staff Id    Total
------------------
1           123.00
2           439.22
Run Code Online (Sandbox Code Playgroud)

我对上述报告使用以下查询:

select 
    user_id as staff_id,
    sum(amount) as total
from transaction
where
    business_id = <business_id> and
    type = 'staff' and
    kind = 'commission' and
    created_at between <start_date> and <end_date>
group by
    user_id;
Run Code Online (Sandbox Code Playgroud)

我正在尝试根据以下要求确定优化此查询性能的最佳方法:

  • 结果将根据business_idstart_dateend_date
  • 数据应该始终是新鲜的

看来视图和函数都可以完成这项工作,但我并不能 100% 确定哪种方法是考虑到需求的最佳方法。

旁注:如果能够根据上面提到的参数来缓存数据就太好了,但是数据库方面似乎没有很好的解决方案。如我错了请纠正我!

附加信息:

  • 我正在运行 Postgres 9.6
  • 我在表中的business_idtypekind和列上有索引。这些都是单列、btree 索引。user_idcreated_attransaction

dez*_*zso 6

视图无法帮助您根据未知参数(business_idstart_dateend_date)生成聚合。它只不过是一个给定的查询,永久存储在数据库中以供以后重用。(嗯,实现比较复杂,但这并不影响它们的使用。)

考虑到您的查询,您可以获得的最远视图是

CREATE VIEW staff_commission AS
SELECT 
    user_id AS staff_id,
    business_id,
    amount,
    start_date,
    end_date
FROM transaction
WHERE
    type = 'staff' AND
    kind = 'commission';
Run Code Online (Sandbox Code Playgroud)

事先已知的所有内容都在那里,加上生成所需输出所需的列。

为了获得后者,您必须在任何情况下创建一个函数(可选地,从视图工作)。当您有多个以相同方式过滤日期的查询时,基于视图进行构建是有意义的。

所有这些的性能都将是相同的。索引是否有意义很大程度上取决于实际数据。(不过,我很确定您不需要所有这些。)如果不了解这些,就很难猜测需要哪些改进。尝试一下你所拥有的,检查输出EXPLAIN ANALYZE并看看是否缺少某些东西。

最后关于缓存:PostgreSQL 在这方面非常聪明。深入细节将占据一本书的一两章,但我不会担心这一点,直到我看到太多的磁盘读取(可以从EXPLAIN (ANALYZE, BUFFERS))。