0

我有一个Postgres数据库运行7.4(是的,我们正处于升级之中)获取日,月,年,一生共记录有一个查询W /优化

我有四个单独的查询,以获得日报,每月,每年和终身记录计数

SELECT COUNT(field) 
FROM database 
WHERE date_field 
    BETWEEN DATE_TRUNC('DAY' LOCALTIMESTAMP) 
    AND DATE_TRUNC('DAY' LOCALTIMESTAMP) + INTERVAL '1 DAY' 

单月刚刚与MONTH替换查询单词DAY等,每次持续时间。

寻找关于如何通过一个查询获得所有期望结果的想法以及任何人会推荐的优化。

提前致谢!

注:DATE_FIELD是无时区的时间戳

UPDATE:

抱歉,我过滤掉额外的查询约束的记录,只是想给DATE_FIELD比较的依据。对不起,任何混乱

+0

最明显的答案是加入其他查询的选择。它仍然有4个查询,但是您可以在一次调用中执行此操作,从而减少事务开销。 – corsiKa 2011-05-25 16:33:34

回答

1

我有使用预处理语句和简单的统计数据为(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()函数,你需要更新的统计数据的任何时间。

-1

哎呀!不要这样做!不是因为你不能完成你所要求的,而是因为你可能不应该以这种方式来做你所要求的。我猜你在你的例子中有date_field的原因是因为你有一个date_field附加到用户或其他元数据。

想一想:您正在要求PostgreSQL扫描与给定用户相关的记录的100%。除非这是一次性操作,否则几乎肯定不会这样做。如果这是一次性操作,并且您计划将此值缓存为元数据,那么谁在意优化?空间很便宜,并且可以节省大量执行时间。

您应该为每个用户添加4x(或其他任何元数据)元数据字段,以帮助总结数据。你有两个选择,我会让你想出如何使你保持历史计数使用,但在这里是比较容易的版本:

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不根据NOW()匹配当天。你可以从这里获得创意,但是像这样增加记录会成为一种方式。

处理时间系列数据任何关系数据库需要特殊的处理和维护。如果你想要良好的临时数据管理,那么请考虑PostgreSQL的表继承......但是实际上,不要对你的应用程序做任何事情,因为它几乎肯定会导致不好的事情(tm)。

+0

sry也许我应该提到这不是所有的查询,我用其他查询条件筛选出大量的记录。只是想声明基本的查询功能 – 2011-05-25 18:35:28

+0

这样的日期数据的大扫描附加到“性能”字样几乎总是意味着该应用程序设计错误。在其他地方使用一段元数据,您可以增加和轮询这些数据。真。 :〜] – Sean 2011-05-25 18:38:19

+0

“想一想:您正在要求PostgreSQL扫描与给定用户相关的记录的100%,除非这是一次性操作” - 不是这样。 date_field上的一个索引可以很好地处理这个问题,即使是第7.4页... – 2011-05-25 19:00:35

0

我想这是不可能的,比现在更好地进行优化。

如果你每天收集/每月/每年的统计信息,我假设(当然升级后),你正在做的,一种选择是with statement及相关连接,如:

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

然而,实际上这并不比在生产环境中分别运行每个查询的效果好,因为您将在数据库中引入左连接,这在中间件中也可以完成(即每天显示,然后按月显示,然后按年显示,最后显示终生统计)。 (如果不是更好,因为您将避免全表扫描。)

通过保持好像,您将保存宝贵的DB资源来处理实际数据的读写操作。权衡(数据库与您的应用程序之间的网络流量减少)几乎肯定不值得。

相关问题