PostgreSQL bytea 및 smallint []


9

대규모 (100Mb-1GB) 다중 채널 시계열 데이터를 PostgreSQL 데이터베이스로 가져 오려고합니다. 데이터는 일반적으로 각각 몇 초의 "레코드"또는 "에포크"로 데이터를 청크하는 EDF 형식 파일 에서 가져옵니다 . 각 에포크의 레코드는 각 데이터 채널에 대한 신호를 짧은 정수의 순차적 배열로 보유합니다.

최악의 경우 BLOB로 데이터베이스 내에 파일을 저장해야합니다. 이를 감안할 때 신호 데이터를 기반으로 쿼리를 촉진하는 등 데이터베이스 내의 데이터로 더 많은 작업을 수행 할 수있는 옵션을 조사하고 싶습니다.

나의 초기 계획은 에포크 레코드 당 하나의 행으로 데이터를 저장하는 것입니다. 내가 계량하려고하는 것은 실제 신호 데이터를 bytea 또는 smallint [] (또는 smallint [] []) 유형으로 저장할지 여부입니다. 누구든지 다른 것을 추천 할 수 있습니까? 저장 및 액세스 비용에 관심이 있습니다. 사용법은 한 번만 삽입하고 가끔 읽고 업데이트하지 않을 가능성이 있습니다. 레코드를 비교하는 분석 기능을 추가 할 수 있도록 사용자 정의 유형으로 더 쉽게 정리 된 경우 훨씬 좋습니다.

의심의 여지없이 나는 세부 사항이 낮으므로 명확하게 설명하고 싶은 내용에 대한 의견을 자유롭게 추가하십시오.


2
이는 24-28 바이트 행 오버 헤드를 피함으로써 많은 디스크 공간 을 절약하기 때문에 권한 부여 데이터 모델에서 어레이 사용을위한 합리적인 용도 중 하나 일 수 있습니다 . 어레이는 충분히 길면 압축되어 라인 외부에 저장됩니다.
Craig Ringer

데이터를 저장하는 방법 인 beldaz는 데이터 액세스 방법 및 빈도와 관련이 있습니다. 데이터가 거의 쿼리되지 않고 항상 레코드 단위로 데이터를 가져 오려면 배열의 레코드 당 하나의 행이 적합하다고 생각합니다. 그러나 예를 들어 주어진 patient_id에 대한 모든 레코드를 가져 오는 등 약간 더 심층적 인 쿼리를 수행하려는 경우 스토리지 구조가 약간 개선 될 수 있습니다. 쿼리 패턴에 대한 아이디어가 있습니까?
Chris

@Chris 감사합니다. 메타 데이터 구성 요소는 매우 작으며 별도의 관계에있을 수 있으므로 생략했습니다. 쿼리 패턴은 TBD이지만 동시에 기록 된 두 개의 다른 파일을 비교하고 동시 에포크에서 신호를 꺼내고 싶을 수 있습니다.
beldaz

@CraigRinger 배열 압축의 많은 증거를 보지 못했습니다. 어떤 식 으로든 활성화해야합니까?
beldaz

답변:


11

답변이 없으면 문제를 직접 탐구했습니다.

사용자 정의 함수 가 and를 포함한 모든 기본 유형을 처리 할 수있는 것처럼 보이 므로 표현 선택에 큰 영향을 미치지 않습니다.byteasmallint[]

바닐라 구성으로 Windows 7 랩톱에서 로컬로 실행되는 PostgreSQL 9.4 서버에서 여러 가지 다른 표현을 시도했습니다. 실제 신호 데이터를 저장하는 관계는 다음과 같습니다.

전체 파일을위한 큰 객체

CREATE TABLE BlobFile (
    eeg_id INTEGER PRIMARY KEY,
    eeg_oid OID NOT NULL
);

채널당 SMALLINT 어레이

CREATE TABLE EpochChannelArray (
    eeg_id INT NOT NULL,
    epoch INT NOT NULL,
    channel INT,
    signal SMALLINT[] NOT NULL,
    PRIMARY KEY (eeg_id, epoch, channel)
);

각 시대의 채널당 BYTEA

CREATE TABLE EpochChannelBytea (
    eeg_id INT NOT NULL,
    epoch INT NOT NULL,
    channel INT,
    signal BYTEA NOT NULL,
    PRIMARY KEY (eeg_id, epoch, channel)
);

에포크 당 SMALLINT 2D 어레이

CREATE TABLE EpochArray (
    eeg_id INT NOT NULL,
    epoch INT NOT NULL,
    signals SMALLINT[][] NOT NULL,
    PRIMARY KEY (eeg_id, epoch)
);

에포크 당 BYTEA 어레이

CREATE TABLE EpochBytea (
    eeg_id INT NOT NULL,
    epoch INT NOT NULL,
    signals BYTEA NOT NULL,
    PRIMARY KEY (eeg_id, epoch)
);

그런 다음 Java JDBC를 통해 선택한 EDF 파일을 각 관계로 가져오고 각 업로드 후 데이터베이스 크기의 증가를 비교했습니다.

파일은 다음과 같습니다.

  • 파일 A : 16 채널 2706 에포크, 각 채널 1024 샘플 (에포크 당 1,16385 샘플), 85 MB
  • 파일 B : 18 채널의 11897 에포크, 각 채널 1024 샘플 (에포크 당 18332 샘플), 418 MB
  • 파일 C : 20746 개 채널의 11746 개 에포크, 각 채널 64 ~ 1024 개 샘플 (에포크 당 17088 개 샘플), 382MB

스토리지 비용 측면에서 다음은 각 사례에서 차지하는 크기 (MB)입니다. MB 단위의 저장 비용

원래 파일 크기에 비해 큰 개체는 약 30-35 % 더 큽니다. 반대로, 각 시대를 BYTEA 또는 SMALLINT [] []로 저장하면 10 % 미만이되었습니다. 각 채널을 별도의 튜플로 저장하면 BYTEA 또는 SMALLINT []로 40 % 증가하므로 큰 객체로 저장하는 것보다 나쁘지 않습니다.

내가 처음에 알지 못했던 한 가지는 PostgreSQL에서 "다차원 배열이 각 차원마다 일치하는 범위를 가져야한다"는 것입니다 . 이는 SMALLINT[][]에포크의 모든 채널에 동일한 수의 샘플이있는 경우에만 표현 이 작동 함을 의미합니다 . 따라서 파일 C는 EpochArray관계에 대해 작동하지 않습니다 .

액세스 비용 등의 측면에서,이 주위에 연주하지만, 적어도 초기에 가장 빠르게 표현이었다 데이터를 삽입 측면에서하지 EpochByteaBlobFile함께, EpochChannelArray처음 두대로만큼 3 번에 대한 고려, 가장 느린.


학문적 인 관점에서, 나는 당신의 결과가 매우 흥미 롭다고 생각하지만, 실제적인 관점에서 저장 공간 크기가 큰 관심사입니까? 아마도 유스 케이스에 많은 레코드가 있으므로 스토리지가 문제가됩니까? 그러나이 스토리지 형식에서 epoch (또는 적절한 스키마에있을 때 채널) 이외의 조회는 모든 레코드의 일부를 읽어야합니다. 응용 프로그램에 적합합니까?
Chris

실제로 몇 TB의 원시 파일을 처리 할 것으로 예상되므로 실제로 중요합니다. 오버 헤드의 전류가 예상보다 낮다는 것이 밝혀졌지만 특정 표현에 대해 300 %라면 분명히 피할 것입니다. 쿼리에 관해서는 시대와 채널 이외의 다른 것으로 액세스 할 것으로 기대하지 않습니다.
beldaz
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.