我有一张ID,日期,值的大表。它有大约30,000个ID,日期是不完整的工作日的20年(缺少假期和一些随机数据)。对于给定的ID和日期列表,我正在查找这些日期最近的值。我的代码可以运行,但是速度很慢,我想知道是否可以对其进行实质性的改进。
以下代码设置了该问题的虚拟版本。而不是平日,我只是每隔一天生成一次数据。请原谅我可怜的代码,我不是Postgresql本机。
CREATE TABLE public.testtable
(
myid character(8) COLLATE pg_catalog."default" NOT NULL,
mydate date NOT NULL,
myvalue double precision,
CONSTRAINT testtable_pkey PRIMARY KEY (myid, mydate)
)
WITH (
OIDS = FALSE
)
TABLESPACE pg_default;
CREATE UNIQUE INDEX testtable_index
ON public.testtable USING btree
(myid COLLATE pg_catalog."default", mydate)
TABLESPACE pg_default;
ALTER TABLE public.testtable
CLUSTER ON testtable_index;
-- insert some test data
DO $$
BEGIN
FOR counter IN 1..100 LOOP
insert into testtable
SELECT array_to_string(ARRAY(SELECT chr((65 + round(random() * 25)) :: integer) FROM generate_series(1,8)), '') as myid, dates.mydate, dates.mydate - '1998-12-31' as myvalue
from (SELECT date_trunc('day', dd)::date as mydate
FROM generate_series
( '1999-01-01'::date
, '2019-01-01'::date
, '2 days'::interval) dd) as dates;
END LOOP;
END; $$
接下来,我得到最小的ID,并将其放入选择查询中。实际上,我将在此处输入不同的ID,以获取该ID的系列。
select distinct on (x.search_dates)
x.search_dates, t1.myid, t1.mydate, t1.myvalue
from (SELECT date_trunc('day', dd)::date as search_dates
FROM generate_series
( '2008-01-01'::date
, '2018-01-01'::date
, '1 week'::interval) dd) as x
left join public.testtable t1 on t1.mydate <= x.search_dates and t1.mydate >= x.search_dates - INTERVAL '7 days'
where t1.myid = (select min(myid) from testtable) -- replace with specific id
order by x.search_dates, t1.mydate desc
这会产生我所追求的输出,并且其速度本身还不错,但是我正在依次查询所有30,000个id,这已经花费了数小时。
主要问题是在这种情况下是否有更好的命中索引的方法来加快速度?当我对此查询运行EXPLAIN时,其中存在一个嵌套循环,该循环处理的行数超过40万(在示例中),我不确定是什么产生的。
我想更广泛的问题是,我在寻找不精确的比赛是否意味着这总是很慢?如果是这样,是否有更好的数据库/数据存储方法更适合此时间序列数据?数据的最终目标是R,所以我对其他方法很开放。
谢谢。