我已经获得了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天包含300k行。
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
如何改善查询?我可以创建索引吗?
UPD:
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
答案 0 :(得分:3)
由于您只关心整天,您可能希望将结果缓存在物化视图中。
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
答案 1 :(得分:1)
您可以使用覆盖索引,即使用仅索引扫描强制执行程序。
对于覆盖索引,您可以先添加在where子句中使用的列,然后在group by中使用列,然后按顺序使用列,然后在select中使用列。
ALTER TABLE session ADD KEY ix1(date(associationtime), <remaining_columns>);
其中<remaining_columns>
是那些,您可以在SFW语句的group by
子句中写入。
答案 2 :(得分:1)
从associationtime
删除日期转换,以便索引能够流行起来。
SELECT cast(AVG(SNR) AS integer) AS snr,
cast(AVG(RSSI) AS integer) AS rts
FROM SESSION
WHERE associationtime > DATE(NOW() - INTERVAL '20 DAYS');
如果这对VACUUM ANALYZE
没有帮助,请再试一次。