sql - 如何改进这个 Postgres 查询?

标签 sql postgresql

我有 sql 查询:

SELECT cast(AVG(SNR) AS integer) AS snr,
       cast(AVG(RSSI) AS integer) AS rts
FROM SESSION
WHERE DATE(associationtime)>DATE(NOW()- INTERVAL '21 DAYS');

它运行缓慢,因为 21 天包含 30 万行。

 Aggregate  (cost=21768.07..21768.09 rows=1 width=8) (actual time=346.794..346.795 rows=1 loops=1)
   ->  Seq Scan on session  (cost=0.00..20095.77 rows=334459 width=8) (actual time=0.014..282.512 rows=345304 loops=1)
         Filter: (date(associationtime) > date((now() - '21 days'::interval)))
         Rows Removed by Filter: 148508
 Total runtime: 346.867 ms

如何改进我的查询?我可以创建索引或其他东西吗?

更新:

associationtime 上的索引没有帮助。

postgres=# CREATE INDEX session_lim_values_idx ON session (associationtime);
CREATE INDEX
postgres=# EXPLAIN (ANALYZE) SELECT cast(AVG(SNR) as integer) as snr, cast(AVG(RSSI) as integer)  as rts FROM session WHERE DATE(associationtime)>DATE(NOW()- INTERVAL '21 DAYS');
                                                      QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost=21768.07..21768.09 rows=1 width=8) (actual time=347.654..347.654 rows=1 loops=1)
   ->  Seq Scan on session  (cost=0.00..20095.77 rows=334459 width=8) (actual time=0.014..283.344 rows=345304 loops=1)
         Filter: (date(associationtime) > date((now() - '21 days'::interval)))
         Rows Removed by Filter: 148508
 Total runtime: 347.731 ms

还有DATE(associationtime):

postgres=# CREATE INDEX session_lim_values_idx ON session (DATE(associationtime));
CREATE INDEX
postgres=# EXPLAIN (ANALYZE) SELECT cast(AVG(SNR) as integer) as snr, cast(AVG(RSSI) as integer)  as rts FROM session WHERE DATE(associationtime)>DATE(NOW()- INTERVAL '21 DAYS');
                                                      QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost=21768.07..21768.09 rows=1 width=8) (actual time=341.050..341.050 rows=1 loops=1)
   ->  Seq Scan on session  (cost=0.00..20095.77 rows=334459 width=8) (actual time=0.015..278.247 rows=345304 loops=1)
         Filter: (date(associationtime) > date((now() - '21 days'::interval)))
         Rows Removed by Filter: 148508
 Total runtime: 341.129 ms

最佳答案

因为您只关心整天,所以您可能希望将结果缓存在物化 View 中。

CREATE MATERIALIZED VIEW matview_avg_session
AS SELECT cast(AVG(SNR) AS integer) AS snr,
   cast(AVG(RSSI) AS integer) AS rts
   FROM SESSION
   WHERE DATE(associationtime) > DATE(NOW()- INTERVAL '21 DAYS');

然后像这样访问数据:

SELECT * FROM matview_avg_session;

并像这样刷新它(每天自动一次):

REFRESH MATERIALIZED VIEW matview_avg_session;

或者您查看有关如何创建用于刷新它的触发器的答案,但请记住,您不想在每次插入后都执行此操作... Refresh a materialized view automatically using a rule or notify

关于sql - 如何改进这个 Postgres 查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24732261/

相关文章:

mysql - 带有空格的用户电子邮件,用 MySQL 修复?

sql - 从另一个表更新一个表

c# - WCF是否缓存存储过程

arrays - Postgres 不在数组中

sql - Postgres 中的慢速查询优化

django - Django 上具有子域的多个 PostgreSQL 架构和用户

sql - 加密 SQL Server 中现有的列数据

sql - Snowflake 如何对字段数组运行逆透视查询而不是显式声明每个字段?

ruby-on-rails - 如何使用 has_one 创建关联记录和修改数据

node.js - 如何在sequelizejs中创建具有关联的模型实例?