通过一个查询带有优化来获得日,月,年,寿命的总记录

问题描述

|| 我有一个运行7.4的Postgres DB(是的,我们正在升级中) 我有四个单独的查询获取每日,每月,每年和终身记录计数
SELECT COUNT(field)
FROM database
WHERE date_field
    BETWEEN DATE_Trunc(\'DAY\' LOCALTIMESTAMP) 
    AND DATE_Trunc(\'DAY\' LOCALTIMESTAMP) + INTERVAL \'1 DAY\'
对于Month,只需在查询中将单词
DAY
替换为
MONTH
,依此类推。 寻找有关如何通过一个查询以及建议的任何优化来获得所有期望结果的想法。 提前致谢! 注意:date_field是没有时区的时间戳 更新: 抱歉,我确实要过滤掉具有其他查询约束的记录,只想给出date_field比较的要点。抱歉造成任何混乱     

解决方法

我对使用准备好的语句和简单的统计信息(record_count_t)表有一些想法:
-- DROP TABLE IF EXISTS record_count_t;
-- DEALLOCATE record_count;
-- DROP FUNCTION updateRecordCounts();

CREATE TABLE record_count_t (type char,count bigint);
INSERT INTO record_count_t (type) VALUES (\'d\'),(\'m\'),(\'y\'),(\'l\');

PREPARE record_count (text) AS
UPDATE record_count_t SET count =
(SELECT COUNT(field)
FROM database
WHERE
CASE WHEN $1 <> \'l\' THEN
    DATE_TRUNC($1,date_field) = DATE_TRUNC($1,LOCALTIMESTAMP)
ELSE TRUE END)
WHERE type = $1;

CREATE FUNCTION updateRecordCounts() RETURNS void AS
$$
    EXECUTE record_count(\'d\');
    EXECUTE record_count(\'m\');
    EXECUTE record_count(\'y\');
    EXECUTE record_count(\'l\');
$$
LANGUAGE SQL;

SELECT updateRecordCounts();
SELECT type,count FROM record_count_t;
每当需要更新统计信息时,请使用updateRecordCounts()函数。     ,我猜想不可能对此进行进一步优化。 如果您要收集每日/每月/每年的统计信息(如我所假设的那样),则一个选项(当然,在升级后)是with语句和相关的联接,例如:
with daily_stats as (
(what you posted)
),monthly_stats as (
(what you posted monthly)
),etc.
select daily_stats.stats,monthly_stats.stats,etc.
stats
left join yearly_stats on ...
left join monthly_stats on ...
left join daily_stats on ...
但是,这实际上要比在生产环境中单独运行每个查询的效果差,因为您将在数据库中引入左联接,这在中间件中也可以做到(即每天显示,然后每月显示,然后每年显示,最后一生的统计数据)。 (如果不是更好的话,因为您将避免全表扫描。) 通过保持一致,您将节省宝贵的数据库资源来处理对实际数据的读写。折衷(减少数据库与应用程序之间的网络流量)绝对不值得。     ,kes!不要这样做!!!不是因为您不能做自己要问的事情,而是因为您可能不应该以这种方式做自己要问的事情。我想在您的示例中获得ѭ5的原因是因为您已将ѭ5附加到用户或某些其他元数据。 想想看:您正在要求PostgreSQL扫描与给定用户相关的100%记录。除非这是一次性操作,否则您几乎可以肯定不想这样做。如果这是一次操作,并且您打算将该值作为元数据进行缓存,那么谁在乎优化呢?空间很便宜,可以节省大量的执行时间。 您应该为每位用户添加4倍(或其他)元数据字段,以帮助汇总数据。您有两个选择,我将让您弄清楚如何使用它,以便保留历史数据,但这是简单的版本:
CREATE TABLE user_counts_only_keep_current (
  user_id,-- Your user_id
  lifetime INT DEFAULT 0,yearly INT DEFAULT 0,monthly INT DEFAULT 0,daily INT DEFAULT 0,last_update_utc TIMESTAMP WITH  TIME ZONE,FOREIGN KEY(user_id) REFERENCES \"user\"(id)
);
CREATE UNIQUE INDEX this_tbl_user_id_udx ON user_counts_only_keep_current(user_id);
设置一些存储过程,如果
last_update_utc
与day9ѭ的当前日期不匹配,则将各个列清零。您可以从这里获得创意,但是增加记录这样的方式将是必经之路。 在任何关系数据库中处理时间序列数据都需要特殊的处理和维护。如果想要良好的临时数据管理,请查看PostgreSQL的表继承...。但是,实际上,不要对应用程序执行任何操作,因为它几乎肯定会导致不良后果(tm)。