시계열 데이터를 저장하는 '최상의 방법'은 실제로 없으며 여러 가지 요인에 따라 정직하게 결정됩니다. 그러나 두 가지 요소에 주로 중점을 두겠습니다.
(1)이 프로젝트가 스키마를 최적화하려는 노력을 기울여야 할만큼 얼마나 심각합니까?
(2) 쿼리 액세스 패턴은 실제로 어떤 모양입니까?
이러한 질문을 염두에두고 몇 가지 스키마 옵션을 살펴 보겠습니다.
플랫 테이블
플랫 테이블을 사용하는 옵션은 question (1) 과 관련이 있습니다.이 프로젝트가 심각하거나 대규모 프로젝트가 아닌 경우 스키마에 대해 너무 많이 생각하지 않는 것이 훨씬 쉽습니다. 평평한 테이블을 사용하십시오.
CREATE flat_table(
trip_id integer,
tstamp timestamptz,
speed float,
distance float,
temperature float,
,...);
이 과정을 추천하는 경우는 많지 않습니다. 시간이 많이 걸리지 않는 작은 프로젝트 인 경우에만 가능합니다.
차원과 사실
따라서 (1) 의 문제를 해결하고 더 많은 성능 스키마를 원한다면 이것이 가장 먼저 고려해야 할 옵션 중 하나입니다. 여기에는 기본 규범화가 포함되지만 측정 된 'fact'수량에서 '치수'수량을 추출합니다.
기본적으로 여행에 대한 정보를 기록하는 테이블이 필요합니다.
CREATE trips(
trip_id integer,
other_info text);
타임 스탬프를 기록하는 테이블,
CREATE tstamps(
tstamp_id integer,
tstamp timestamptz);
마지막으로 차원 테이블에 대한 외래 키 참조 ( meas_facts(trip_id)
참조 trips(trip_id)
및 meas_facts(tstamp_id)
참조 tstamps(tstamp_id)
) 와 함께 모든 측정 사실
CREATE meas_facts(
trip_id integer,
tstamp_id integer,
speed float,
distance float,
temperature float,
,...);
처음에는 그다지 도움이되지 않는 것처럼 보일 수 있지만, 예를 들어 수천 번의 동시 트립이있는 경우 두 번째에서 초당 한 번씩 측정을 수행 할 수 있습니다. 이 경우 tstamps
테이블 의 단일 항목을 사용하지 않고 각 여행에 대해 매번 타임 스탬프를 다시 기록해야 합니다.
사용 사례 : 데이터를 기록하는 동시 트립이 많고 모든 측정 유형에 모두 액세스하는 것이 마음에 들지 않으면이 경우가 좋습니다.
Postgres는 행 단위로 읽으므로 원하는 speed
시간 범위에 대한 측정 과 같이 원하는 시간마다 meas_facts
테이블 에서 전체 행을 읽어야합니다.이 경우 작업하는 데이터 세트가 너무 크지 않으면 차이를 느끼지 못할 것입니다.
측정 된 사실 나누기
마지막 섹션을 조금 더 확장하기 위해 측정 값을 별도의 테이블로 분리 할 수 있습니다. 예를 들어 속도와 거리에 대한 테이블을 표시하겠습니다.
CREATE speed_facts(
trip_id integer,
tstamp_id integer,
speed float);
과
CREATE distance_facts(
trip_id integer,
tstamp_id integer,
distance float);
물론 이것이 다른 측정으로 어떻게 확장되는지 알 수 있습니다.
사용 사례 : 따라서 쿼리 속도가 엄청나게 향상되지는 않으며, 한 가지 측정 유형에 대해 쿼리 할 때 속도가 선형 적으로 증가 할 수도 있습니다. 속도에 대한 정보를 찾으려면 speed_facts
테이블의 행에있는 불필요한 정보가 아닌 테이블 에서 행을 읽어야 하기 때문 meas_facts
입니다.
따라서 하나의 측정 유형에 대해서만 방대한 양의 데이터를 읽어야하므로 이점을 얻을 수 있습니다. 1 초 간격으로 10 시간 분량의 데이터를 제안하면 36,000 개의 행만 읽을 수 있으므로이 작업을 수행하면 큰 이점을 얻을 수 없습니다. 그러나 약 10 시간 동안 5,000 회 여행에 대한 속도 측정 데이터를 살펴 보려면 이제 1 억 8 천만 행을 읽는 중입니다. 한 번에 하나 또는 두 개의 측정 유형에만 액세스해야하는 한, 이러한 쿼리에 대한 선형 속도 증가는 몇 가지 이점을 제공 할 수 있습니다.
어레이 / HStore / 및 TOAST
이 부분에 대해 걱정할 필요는 없지만 중요한 부분은 알고 있습니다. 당신이 액세스해야하는 경우 거대한 시계열 데이터의 양, 당신은 당신이 하나 개의 거대한 블록에 모두 접근 할 필요가 알고, 당신은 사용하게하는 구조를 사용할 수 있습니다 TOAST 테이블 압축 본질적으로 더 큰에서 데이터를 저장, 세그먼트. 따라서 모든 데이터에 액세스하는 것이 목표 인 한 데이터에 더 빠르게 액세스 할 수 있습니다.
한 가지 구현 예는 다음과 같습니다.
CREATE uber_table(
trip_id integer,
tstart timestamptz,
speed float[],
distance float[],
temperature float[],
,...);
이 표 tstart
에서 첫 번째 항목의 타임 스탬프를 배열에 저장하고 이후의 각 항목은 다음 초의 값이됩니다. 이를 위해서는 애플리케이션 소프트웨어에서 각 어레이 값에 대한 관련 타임 스탬프를 관리해야합니다.
또 다른 가능성은
CREATE uber_table(
trip_id integer,
speed hstore,
distance hstore,
temperature hstore,
,...);
여기서 측정 값을 (키, 값) 쌍의 (타임 스탬프, 측정)으로 추가합니다.
유스 케이스 : 이것은 PostgreSQL에 더 익숙한 사람에게 더 나은 구현 일 것입니다. 액세스 패턴이 벌크 액세스 패턴이어야하는 것이 확실한 경우에만 가능합니다.
결론?
와우, 이건 내가 예상했던 것보다 훨씬 길었어, 미안 :)
기본적으로 여러 가지 옵션이 있지만 더 일반적인 경우에 따라 두 번째 또는 세 번째를 사용하여 벅에 가장 큰 타격을 줄 것입니다.
추신 : 첫 번째 질문은 데이터가 모두 수집 된 후에 데이터를 대량로드한다는 것을 암시합니다. PostgreSQL 인스턴스에 데이터를 스트리밍하는 경우 데이터 수집 및 쿼리 워크로드를 모두 처리하기 위해 몇 가지 추가 작업을 수행해야하지만 다른 시간에는 그대로 두겠습니다. ;)