Postgres 데이터베이스 확장은 애플리케이션 성장을 위한 통과 의례입니다. 테이블이 수백만 또는 심지어 수십억 개의 행으로 확장되는 것을 보면 한때 신속했던 쿼리가 지연되기 시작하고 증가하는 인프라 비용으로 인해 수익에 긴 그림자가 드리워지기 시작합니다. 당신은 난제에 빠졌습니다. 당신은 사랑하는 PostgreSQL과 헤어지고 싶지 않지만, 증가하는 데이터 세트를 처리하기 위한 보다 효과적인 방법이 필요한 것 같습니다.
이 기사에서는 확장성을 향상시키기 위해 PostgreSQL용 유연한 고성능 열 압축 메커니즘을 구축한 방법에 대해 설명합니다. 컬럼형 스토리지와 특수 압축 알고리즘을 결합함으로써 다른 관계형 데이터베이스와 비교할 수 없는 인상적인 압축률(+95%)을 달성할 수 있습니다.
데이터 세트를 압축하면 PostgreSQL 데이터베이스를 더욱 확장할 수 있습니다. 이 기사 전체에서 살펴보겠지만, 이 매우 효과적인 압축 설계를 통해 대규모 PostgreSQL 테이블의 크기를 최대 10-20배까지 줄일 수 있습니다. 쿼리 성능을 향상시키면서 더 작은 디스크에 훨씬 더 많은 데이터를 저장할 수 있습니다(즉, 비용 절감). 시간 척도 압축은 완전히 변경 가능하므로 데이터베이스 관리 및 운영이 쉬워집니다. 압축된 테이블의 열을 추가, 변경 및 삭제할 수 있으며 데이터를 직접 INSERT, UPDATE 및 DELETE할 수 있습니다.
더욱 확장 가능한 PostgreSQL에 오신 것을 환영합니다!
segmentby
별 열별로 그룹화segmentby
별 열 정의orderby
통한 고급 미세 조정
그러나 압축을 구축한 방법에 대해 자세히 알아보기 전에 다음 질문에 답하는 데 몇 분을 투자해 보겠습니다. PostgreSQL에 새 데이터베이스 압축 메커니즘을 추가해야 하는 이유는 무엇입니까?
먼저 최신 애플리케이션의 요구 사항과 약간의 소프트웨어 역사를 이해해 보겠습니다.
우리는 Postgres를 좋아합니다. Postgres의 안정성, 유연성 및 풍부한 생태계 조합은 다른 어떤 데이터베이스와도 비교할 수 없기 때문에 애플리케이션 구축을 위한 최고의 기반이라고 믿습니다. 하지만 Postgres는 수십 년 전에 탄생했습니다. 이러한 견고함에도 단점이 없지는 않습니다.
오늘날 개발자들은 가장 잘 알려진 기존 OLTP(온라인 트랜잭션 처리) 사용 사례보다 훨씬 더 많은 용도로 PostgreSQL을 사용하고 있습니다. 연중무휴로 실행되고 점점 늘어나는 데이터 볼륨을 처리하는 많은 데이터 집약적이고 까다로운 애플리케이션이 PostgreSQL을 기반으로 합니다.
PostgreSQL 데이터베이스는 교통 관리 시스템, 유틸리티 네트워크 및 공공 안전 모니터에서 스트리밍되는 방대한 양의 센서 데이터를 수집하는 데 사용되고 있습니다.
에너지 회사는 PostgreSQL을 사용하여 스마트 그리드 및 재생 가능 에너지원의 지표를 저장하고 분석하고 있습니다.
금융 부문에서 PostgreSQL은 시세 데이터를 실시간으로 추적하는 시스템의 핵심입니다.
전자상거래 플랫폼은 PostgreSQL을 사용하여 사용자 상호 작용으로 생성된 이벤트를 추적하고 분석합니다.
Postgres는 AI 애플리케이션의 새로운 물결을 지원하기 위한 벡터 데이터베이스로도 사용되고 있습니다.
결과적으로 Postgres 테이블은 매우 빠르게 성장하고 있으며 테이블이 수십억 행에 도달하는 것은 프로덕션의 새로운 표준입니다.
불행하게도 PostgreSQL은 기본적으로 이러한 대량의 데이터를 처리하기에는 부족합니다. 쿼리 성능이 저하되기 시작하고 데이터베이스 관리가 어려워집니다. 이러한 제한 사항을 해결하기 위해 우리는
PostgreSQL을 위한 고성능 압축 메커니즘을 구축하는 것도 마찬가지로 중요한 잠금 해제였습니다. 끊임없이 증가하는 이러한 데이터 세트는 우수한 성능을 제공하기 어려울 뿐만 아니라 데이터가 축적되면 디스크 용량도 커지고 스토리지 비용도 높아집니다. PostgreSQL에는 솔루션이 필요했습니다.
하지만 PostgreSQL의 기존 TOAST 메소드는 어떻습니까? 놀라운 이름에도 불구하고 🍞😋,
TOAST는 PostgreSQL이 개별 데이터베이스 페이지에 맞지 않는 큰 값을 저장하고 관리하는 데 사용하는 자동 메커니즘입니다. TOAST는 이를 달성하기 위한 기술 중 하나로 압축을 통합하지만 TOAST의 주요 역할은 전반적으로 저장 공간을 최적화하는 것이 아닙니다.
예를 들어, 작은 튜플로 구성된 1TB 데이터베이스가 있는 경우 TOAST는 아무리 세부 조정을 시도하더라도 해당 1TB를 80GB로 체계적으로 전환하는 데 도움이 되지 않습니다. TOAST는 임계값인 2KB를 초과하면 연속적으로 큰 속성을 자동으로 압축하지만 TOAST는 작은 값(튜플)에는 도움이 되지 않으며 한 달이 지난 모든 데이터를 압축하는 등 사용자가 구성할 수 있는 고급 구성을 적용할 수도 없습니다. 특정 테이블에서. TOAST의 압축은 광범위한 테이블이나 데이터 세트 특성이 아닌 개별 열 값의 크기를 엄격하게 기준으로 합니다.
TOAST는 또한 특히 자주 액세스되는 대형 열이 있는 대형 테이블의 경우 상당한 I/O 오버헤드를 발생시킬 수 있습니다. 이러한 경우 PostgreSQL은 TOAST 테이블에서 라인 외부 데이터를 검색해야 합니다. 이는 기본 테이블에 액세스하는 것과 별도의 I/O 작업입니다. PostgreSQL은 기본 테이블에서 TOAST 테이블로의 포인터를 따라가야 하기 때문입니다. 완전한 데이터. 이로 인해 일반적으로 성능이 저하됩니다.
마지막으로 TOAST의 압축은 모든 데이터 유형에 대해 하나의 표준 알고리즘을 사용하므로 특별히 높은 압축률을 제공하도록 설계되지 않았습니다.
TOAST에 대한 이러한 빠른 언급은 데이터를 효과적으로 압축하는 데 있어 PostgreSQL의 한계를 이해하는 데도 도움이 됩니다. 방금 본 것처럼 TOAST의 압축은 데이터를 행 단위로 처리하지만 이 행 중심 아키텍처는 압축 알고리즘이 기반으로 하는 동질성을 분산시켜 압축 작동 방식에 대한 근본적인 한계를 초래합니다. 이것이 스토리지 최적화와 관련하여 관계형 데이터베이스(예: 기본 Postgres)가 종종 부족한 근본적인 이유입니다.
이것을 분석해보자. 전통적으로 데이터베이스는 다음 두 가지 범주 중 하나에 속합니다.
행 기반 데이터베이스는 데이터를 행별로 구성하며 각 행에는 특정 레코드에 대한 모든 데이터가 포함됩니다. 이는 레코드의 삽입, 업데이트 및 삭제가 빈번한 트랜잭션 처리에 최적화되어 있으며 작업에 개별 레코드 또는 작은 데이터 하위 집합(예: 특정 고객에 대한 모든 정보 검색)이 포함되는 OLTP 시스템에 효율적입니다.
반면 에 열 기반("열형"이라고도 함) 데이터베이스는 데이터를 열별로 구성합니다. 각 열은 여러 레코드의 특정 속성에 대한 모든 데이터를 저장합니다. 일반적으로 쿼리에 여러 레코드에 대한 집계 및 작업이 포함되는 OLAP 시스템(온라인 분석 처리)에 최적화되어 있습니다.
이를 예를 들어 설명하겠습니다. user_id
, name
, logins
및 last_login
의 4개 열이 있는 users
테이블이 있다고 가정해 보겠습니다. 이 테이블이 백만 명의 사용자에 대한 데이터를 저장한다면 사실상 백만 개의 행과 네 개의 열을 가지게 되며 각 사용자의 데이터(즉, 각 행)가 디스크에 연속적으로 물리적으로 저장됩니다.
이 행 중심 설정에서는 user_id = 500,000에 대한 전체 행이 연속적으로 저장되므로 검색이 빠릅니다. 결과적으로, 행 저장소에서는 얕은 쿼리와 넓은 쿼리가 더 빨라집니다(예: "사용자 X에 대한 모든 데이터 가져오기").
-- Create table CREATE TABLE users ( user_id SERIAL PRIMARY KEY, name VARCHAR(100), logins INT DEFAULT 0, last_login TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- Assume we have inserted 1M user records into the 'users' table -- Shallow-and-wide query example (faster in row store) SELECT * FROM users WHERE user_id = 500000;
대조적으로, 컬럼형 저장소는 모든 user_id
, 모든 이름, 모든 로그인 값 등을 함께 저장하므로 각 열의 데이터가 디스크에 연속적으로 저장됩니다. 이 데이터베이스 아키텍처는 "모든 사용자의 평균 로그인 수 계산"과 같은 심층적이고 좁은 쿼리를 선호합니다.
-- Deep-and-narrow query example (faster in column store) SELECT AVG(logins) FROM users;
컬럼형 저장소는 넓은 데이터에 대한 좁은 쿼리에 특히 효과적입니다. 열 기반 데이터베이스에서는 평균을 계산하기 위해 logins
열 데이터만 읽어야 하며, 이는 디스크에서 각 사용자에 대한 전체 데이터 세트를 로드할 필요 없이 수행할 수 있습니다.
지금쯤 짐작하셨겠지만, 데이터를 행과 열에 저장하는 것도 데이터를 얼마나 잘 압축할 수 있는지에 영향을 미칩니다. 열 기반 데이터베이스에서 개별 데이터 열은 일반적으로 동일한 유형이며 더 제한된 도메인이나 범위에서 추출되는 경우가 많습니다.
결과적으로 열 기반 저장소는 일반적으로 행 기반 데이터베이스보다 더 잘 압축됩니다. 예를 들어 이전의 logins
열은 모두 정수 유형이었으며 아마도 작은 범위의 숫자 값으로 구성되었을 것입니다(따라서 엔트로피가 낮아 압축이 잘 됩니다). 전체 데이터 행이 다양한 데이터 유형과 범위로 구성되는 행 기반 형식과 비교해 보세요.
그러나 OLAP 스타일 쿼리 및 압축성 측면에서 이점을 보여주더라도 열 기반 저장소에는 절충점이 없는 것은 아닙니다.
개별 행을 검색하는 쿼리는 성능이 훨씬 낮습니다(때로는 실행이 불가능할 수도 있음).
이들 아키텍처는 기존 ACID 트랜잭션에 적합하지 않습니다.
기둥형 저장소에서는 업데이트를 수행할 수 없는 경우가 많습니다.
행 기반 상점에서는 다음을 활용하는 것이 더 쉽습니다.
행 저장소를 사용하면 데이터 세트를 더 쉽게 정규화할 수 있으므로 관련 데이터 세트를 다른 테이블에 더 효율적으로 저장할 수 있습니다.
그렇다면 행 지향 또는 열 지향 중 무엇이 더 낫습니까?
전통적으로는 워크로드에 따라 둘 사이의 장단점을 평가했습니다. 일반적인 OLTP 사용 사례를 실행하는 경우 아마도 PostgreSQL과 같은 행 기반 관계형 데이터베이스를 선택할 것입니다. 사용 사례가 확실히 OLAP인 경우 ClickHouse와 같은 컬럼형 저장소를 선호할 수 있습니다.
하지만 워크로드가 실제로 두 가지가 혼합된 경우에는 어떻게 될까요?
애플리케이션 쿼리는 일반적으로 여러 장치/서버/항목의 데이터뿐만 아니라 많은 데이터 열에 액세스하는 개별 쿼리를 사용하여 얕고 광범위할 수 있습니다. 예를 들어 특정 제조 공장의 모든 센서에 대해 마지막으로 기록된 온도 및 습도를 표시해야 하는 사용자 대상 시각화를 강화할 수 있습니다. 이러한 쿼리는 작성 기준과 일치하는 모든 행에 걸쳐 잠재적으로 수천 또는 수백만 개의 레코드에 걸쳐 있는 여러 열에 액세스해야 합니다.
그러나 일부 쿼리는 장기간에 걸쳐 특정 센서에 대해 더 적은 수의 열을 선택하는 개별 쿼리를 사용하여 깊고 좁을 수도 있습니다. 예를 들어 이상 현상을 검사하기 위해 지난 달 특정 장치의 온도 추세를 분석해야 할 수도 있습니다. 이 유형의 쿼리는 단일 열(온도)에 초점을 맞추지만 목표 기간 동안 각 시간 간격에 해당하는 많은 수의 행에서 이 정보를 검색해야 합니다.
애플리케이션은 데이터 집약적이고 삽입(추가) 작업이 많을 수도 있습니다. 이전에 논의한 것처럼 초당 수십만 건의 쓰기를 처리하는 것이 새로운 표준입니다. 데이터 세트도 매우 세분화되어 있을 수 있습니다. 예를 들어 매초마다 데이터를 수집할 수 있습니다. 이전 예를 계속하면 데이터베이스는 실시간으로 사용자 대상 시각화를 강화하기 위해 지속적인 읽기와 함께 이러한 대량 쓰기를 처리해야 합니다.
귀하의 데이터는 대부분 추가 되지만 반드시 추가 전용일 필요는 없습니다. 때때로 오래된 레코드를 업데이트해야 하거나 늦게 도착하거나 순서가 잘못된 데이터를 기록해야 할 수도 있습니다.
이 워크로드는 전통적인 의미의 OLTP도 아니고 OLAP도 아닙니다. 대신 두 가지 요소가 모두 포함됩니다. 그래서 뭐 할까?
하이브리드로 가세요!
이전 예와 같은 워크로드를 제공하려면 단일 데이터베이스에 다음이 포함되어야 합니다.
초당 수십만 번의 쓰기에서 쉽게 높은 삽입 속도를 유지할 수 있는 능력
지연되거나 순서가 잘못된 데이터 삽입 및 기존 데이터 수정 지원
대규모 데이터 세트에서 얕은 쿼리와 깊고 좁은 쿼리를 모두 효율적으로 처리할 수 있는 충분한 유연성
데이터베이스 크기를 상당히 줄여 스토리지 효율성을 향상시킬 수 있는 압축 메커니즘
이것이 TimescaleDB(따라서 PostgreSQL)에 열 형식 압축을 추가할 때 달성하려는 목표입니다.
이전 섹션에서 언급했듯이, 더 나은 성능과 확장성으로 PostgreSQL을 확장하여 다음과 같은 까다로운 워크로드에 적합하도록 TimescaleDB를 구축했습니다.
이론적으로 이는 TimescaleDB가 적당한 압축률로 PostgreSQL의 행 중심 스토리지 형식에도 고정되어 있음을 의미합니다. 실제로는 약간의 엔지니어링으로 해결할 수 없는 것이 없습니다.
두 가지 관찰. 첫 번째,
실제로 이 행-열 변환은 전체 데이터베이스에 적용할 필요가 없습니다. Timescale 사용자는 PostgreSQL 테이블을 하이브리드 행-열 저장소로 변환하여 열 형식으로 압축할 데이터를 정확하게 선택할 수 있습니다.
예를 들어 이것이 실제로 어떻게 작동하는지 설명해 보겠습니다. 여러 장치에서 매초 판독값을 수집하고 타임스탬프, 장치 ID, 상태 코드 및 온도와 같은 데이터를 저장하는 온도 모니터링 시스템을 상상해 보십시오.
특히 다양한 장치의 최신 판독값을 분석하려는 운영 쿼리의 경우 최신 온도 데이터에 효율적으로 액세스하려면 기존의 압축되지 않은 행 중심 PostgreSQL 구조에 최신 데이터(예: 지난주)를 보관할 수 있습니다. . 이는 높은 수집 속도를 지원하며 최근 데이터에 대한 포인트 쿼리에도 적합합니다.
-- Find the most recent data from a specific device SELECT * FROM temperature_data WHERE device_id = 'A' ORDER BY timestamp DESC LIMIT 1; -- Find all devices in the past hour that are above a temperature threshold SELECT DISTINCT device_id, MAX(temperature) FROM temperature WHERE timestamp > NOW() - INTERVAL '1 hour' AND temperature > 40.0;
그러나 이 데이터가 며칠이 지나면 이전 쿼리와 같은 얕은 및 넓은 쿼리는 더 이상 자주 실행되지 않습니다. 대신 깊고 좁은 분석 쿼리가 더 일반적입니다. 따라서 이러한 유형의 쿼리에 대한 스토리지 효율성과 쿼리 성능을 향상시키기 위해 1주일이 지난 모든 데이터를 고도로 압축된 열 형식으로 자동 변환하도록 선택할 수 있습니다. Timescale에서 그렇게 하려면 다음과 같은 압축 정책을 정의합니다.
-- Add a compression policy to compress temperature data older than 1 week SELECT add_compression_policy('temperature_data', INTERVAL '7 days');
데이터가 압축되면 온도 데이터(특정 장치 또는 여러 장치에 걸쳐)에 대해 심층적이고 좁은 분석 쿼리를 실행하면 최적의 쿼리 성능이 표시됩니다.
-- Find daily max temperature for a specific device across past year SELECT time_bucket('1 day', timestamp) AS day, MAX(temperature) FROM temperature_data WHERE timestamp > NOW() - INTERVAL '1 year' AND device_id = 'A' ORDER BY day; -- Find monthly average temperatures across all devices SELECT device_id, time_bucket('1 month', timestamp) AS month, AVG(temperature) FROM temperature_data WHERE timestamp < NOW() - INTERVAL '2 weeks' GROUP BY device_id, month ORDER BY month;
행 형식에서 열 형식으로의 "전환"을 어떻게 표현합니까? Timescale의 하이퍼테이블은 타임스탬프나 기타 일련 ID 열과 같은 분할 키를 기반으로 데이터를 "청크"로 분할하는 역할을 합니다. 그런 다음 각 청크는 특정 범위의 타임스탬프 또는 해당 분할 키에 대한 기타 값에 해당하는 레코드를 저장합니다. 위의 예에서 온도 데이터는 주별로 분할되어 최신 청크는 행 형식으로 유지되고 이전 주는 모두 열 형식으로 변환됩니다.
이 하이브리드 행-열 스토리지 엔진은 대규모 PostgreSQL 데이터베이스의 쿼리 성능을 최적화하는 동시에 스토리지 공간을 대폭 줄이는 매우 강력한 도구입니다. 이 문서의 뒷부분에서 살펴보겠지만 데이터를 열 형식으로 변환하고 특수 압축 메커니즘을 적용함으로써 분석 쿼리 속도를 높일 수 있을 뿐만 아니라 최대 98%의 압축률을 달성할 수 있습니다. 이것이 귀하의 보관 비용에 어떤 영향을 미칠지 상상해보세요!
쿼리 성능 및 스토리지 절약에 대해 자세히 알아보기 전에 먼저 이 메커니즘이 내부적으로 작동하는 방식, 즉 행에서 열로의 변환이 실제로 수행되는 방식과 열 형식 데이터에 압축이 적용되는 방식을 살펴보겠습니다.
압축 정책이 시작되면 원래 PostgreSQL 하이퍼테이블의 전통적으로 수많은 개별 레코드였던 것(1,000개의 조밀하게 채워진 행을 상상해 보십시오)을 보다 컴팩트한 단일 행 구조로 변환합니다. 이 압축된 형식 내에서 각 속성이나 열은 더 이상 각 행의 단일 항목을 저장하지 않습니다. 대신, 이 1,000개 행에서 모든 해당 값의 연속적이고 순서가 지정된 시퀀스를 캡슐화합니다. 이 1,000개의 행 을 일괄 처리라고 하겠습니다.
이를 설명하기 위해 다음과 같은 테이블을 상상해 보겠습니다.
| Timestamp | Device ID | Status Code | Temperature | |-----------|-----------|-------------|-------------| | 12:00:01 | A | 0 | 70.11 | | 12:00:01 | B | 0 | 69.70 | | 12:00:02 | A | 0 | 70.12 | | 12:00:02 | B | 0 | 69.69 | | 12:00:03 | A | 0 | 70.14 | | 12:00:03 | B | 4 | 69.70 |
이 데이터의 압축을 준비하기 위해 Timescale은 먼저 이 표 형식 데이터를 열 형식 저장소로 변환합니다. 데이터 배치(~1,000개 행)가 주어지면 각 열의 데이터는 배열로 집계되며, 각 배열 요소는 원래 행 중 하나의 값에 해당합니다. 프로세스 결과 단일 행이 생성되며 각 열은 해당 배치의 값 배열을 저장합니다.
| Timestamp | Device ID | Status Code | Temperature | |------------------------------|--------------------|--------------------|-------------------------------| | [12:00:01, 12:00:01, 12...] | [A, B, A, B, A, B] | [0, 0, 0, 0, 0, 4] | [70.11, 69.70, 70.12, 69....] |
압축 알고리즘을 적용하기 전에도 이 형식은 Timescale의 내부 행별 오버헤드를 크게 줄여 스토리지를 즉시 절약합니다. PostgreSQL은 일반적으로 행당 최대 27바이트의 오버헤드를 추가합니다(예: 다중 버전 동시성 제어 또는 MVCC의 경우). 따라서 압축을 하지 않더라도 위의 스키마가 32바이트라면 이전 에 [1,000 * (32 + 27)] ~= 59KB를 차지했던 일괄 처리의 1,000행 데이터는 이제 [1,000 * 32 + 27 을 차지합니다. ] ~= 이 형식에서는 32KB입니다 .
[ 여담 : 더 큰 테이블을 더 작은 배치로 "그룹화"한 다음 각 배치의 열을 (전체 테이블의 열이 아닌) 연속적으로 저장하는 이 개념은 실제로 Apache Parquet 파일 형식의 "행 그룹"과 유사한 접근 방식입니다. 그 유사점은 나중에서야 깨달았지만!]
그러나 이 변환의 가장 큰 장점은 이제 유사한 데이터(타임스탬프, 장치 IDS, 온도 판독값 등)가 연속적으로 저장되는 형식이 주어 지면 유형별 압축 알고리즘을 사용하여 각 배열이 별도로 압축될 수 있다는 것 입니다. . 이것이 Timescale이 인상적인 압축률을 달성하는 방법입니다.
Timescale은 자동으로 다음 압축 알고리즘을 사용합니다. 이 모든 알고리즘은 “
델타-델타 +
몇 가지 반복 값이 있는 열에 대한 전체 행 사전 압축(+ 맨 위에 LZ 압축)
다른 모든 유형에 대한 LZ 기반 배열 압축
우리는 역순으로 데이터 압축 해제를 처리하도록 Gorilla 및 Simple-8b를 확장하여 역방향 스캔을 사용하는 쿼리 속도를 높일 수 있었습니다.
우리는 이 유형별 압축이 매우 강력하다는 것을 확인했습니다. 더 높은 압축성 외에도 Gorilla 및 델타-델타와 같은 일부 기술은 디코딩 중에 LZ 기반 압축보다 최대 40배 더 빠르며 쿼리 성능이 크게 향상됩니다. .
데이터 의 압축을 풀 때 Timescale은 이러한 개별 압축 배치에 대해 작업을 수행하여 요청된 열에 대해서만 일괄적으로 압축을 풀 수 있습니다. 따라서 쿼리 엔진이 원래 100만 행의 데이터가 포함된 테이블 청크에서 20개의 배치(20,000개의 원래 데이터 행에 해당)만 처리해야 한다고 판단할 수 있는 경우 쿼리는 읽고 압축을 풀기 때문에 훨씬 빠르게 실행할 수 있습니다. 데이터가 훨씬 적습니다. 그것이 어떻게 이루어지는지 봅시다.
이전 배열 기반 형식은 문제를 제시합니다. 즉, 쿼리를 해결하기 위해 데이터베이스가 어떤 행을 가져오고 압축을 풀어야 하는가?
온도 데이터 예시를 다시 살펴보겠습니다. 몇 가지 자연적인 유형의 쿼리가 계속해서 등장합니다. 즉, 시간 범위별로 데이터를 선택 및 정렬하거나 장치 ID(WHERE 절 또는 GROUP BY를 통해)를 기준으로 데이터를 선택합니다. 그러한 쿼리를 어떻게 효율적으로 지원할 수 있습니까?
이제 마지막 날의 데이터가 필요한 경우 쿼리는 이제 압축된 배열의 일부인 타임스탬프 데이터를 탐색해야 합니다. 그렇다면 데이터베이스는 최근 날짜의 데이터를 찾기 위해 전체 청크(또는 전체 하이퍼테이블)의 압축을 풀어야 할까요?
또는 압축된 배열(위에 설명됨)로 그룹화된 개별 "배치"를 식별할 수 있더라도 서로 다른 장치의 데이터가 함께 산재되어 있으므로 전체 배열의 압축을 풀어 특정 장치에 대한 데이터가 포함되어 있는지 확인해야 합니까? 이 간단한 접근 방식은 여전히 우수한 압축성을 제공할 수 있지만 쿼리 성능 관점에서는 그다지 효율적이지 않습니다.
열 형식의 특정 쿼리에 대한 데이터를 효율적으로 찾고 압축을 푸는 문제를 해결하려면
segmentby
별 열별로 그룹화 Timescale의 데이터는 처음에 청크 단위로 압축된 열 형식으로 변환된다는 점을 기억하세요. 특정 열을 기준으로 필터링하는 쿼리(예: device_id
로 자주 쿼리)의 효율성을 높이기 위해 이 특정 열을 '
이러한 segmentby
열은 압축된 각 청크 내의 데이터를 논리적으로 분할하는 데 사용됩니다. 위에 표시된 것처럼 임의 값의 압축된 배열을 작성하는 대신 압축 엔진은 먼저 동일한 segmentby
키를 가진 모든 값을 그룹화합니다.
따라서 device_id A에 대한 1,000개 행의 데이터는 단일 압축 행에 저장되기 전에 조밀하게 백업되고, device_id B에 대한 1,000개 행 등이 저장됩니다. 따라서 device_id
segmentby
열로 선택되면 압축된 각 행에는 해당 행에 압축되지 않은 상태로 저장되는 특정 장치 ID에 대한 압축된 열 형식 데이터 배치가 포함됩니다. Timescale은 압축된 청크 내에서 이러한 세그먼트별 값에 대한 인덱스를 추가로 구축합니다.
| Device ID | Timestamp | Status Code | Temperature | |-----------|--------------------------------|-------------|-----------------------| | A | [12:00:01, 12:00:02, 12:00:03] | [0, 0, 0] | [70.11, 70.12, 70.14] | | B | [12:00:01, 12:00:02, 12:00:03] | [0, 0, 4] | [69.70, 69.69, 69.70] |
이러한 연속적인 데이터 저장은 segmentby
열로 필터링된 쿼리의 효율성을 크게 향상시킵니다. device_id
segmentby
별 열인 device_id
로 필터링된 쿼리를 실행할 때 Timescale은 지정된 장치 ID가 있는 청크의 모든 압축된 행을 인덱스를 통해 빠르게 선택할 수 있으며 데이터를 빠르게 건너뜁니다(압축 해제를 방지함) ) 요청된 장치와 관련 없는 데이터입니다.
예를 들어 이 쿼리에서 Timescale은 device_id A에 대한 데이터가 포함된 압축된 행만 효율적으로 찾아 처리합니다.
SELECT AVG(temperature) FROM sensor_data WHERE device_id = 'A' AND time >= '2023-01-01' AND time < '2023-02-01';
또한 Timescale 하이퍼테이블은 청크가 다루는 값의 범위를 지정하는 각 청크와 관련된 메타데이터를 저장합니다. 따라서 하이퍼테이블이 주별로 타임스탬프로 분할된 경우 쿼리 플래너가 위 쿼리를 실행할 때 1월에 해당하는 4~5개의 청크만 처리하는 것을 알고 쿼리 성능이 더욱 향상됩니다.
segmentby
별 열 정의하이퍼테이블 압축을 처음 활성화할 때 세그먼트별에 사용할 열을 지정할 수 있습니다. 사용할 열은 쿼리에 자주 사용되는 열을 기준으로 선택해야 합니다. 실제로 여러 열을 사용하여 분류할 수 있습니다. 예를 들어 배치를 device_id별로 그룹화하는 대신 동일한 테넌트_id와 device_id를 모두 갖는 배치를 그룹화할 수 있습니다.
그러나 선택성을 과도하게 사용하지 않도록 주의하십시오. 세그먼트별 열을 너무 많이 정의하면 각 추가 세그먼트별 열이 데이터를 더 작은 배치로 효과적으로 분할하므로 압축 효율성이 감소합니다.
더 이상 1,000개의 데이터 레코드 배치를 생성할 수 없고 대신 특정 청크 내에 지정된 세그먼트별 키가 있는 5개의 레코드만 있는 경우 전혀 압축이 잘 되지 않습니다!
그러나 분할하려는 열을 식별한 후에는 하이퍼테이블에서 압축을 활성화할 때 구성하기가 간단합니다.
ALTER TABLE temperature_data SET ( timescaledb.compress, timescaledb.compress_segmentby = 'device_id' );
orderby
통한 고급 미세 조정 TimescaleDB는 compress_orderby
매개변수에 따라 각 청크 내의 전략적 데이터 순서 지정을 통해 압축된 데이터에 대한 쿼리 성능을 향상시킵니다. 타임스탬프(시계열 데이터의 일반적인 분할 키)를 기준으로 정렬하는 기본 설정은 대부분의 시나리오에 적합하지만 이 최적화를 이해하는 것이 중요할 수 있습니다. 더 깊은 기술적 관점을 읽어보세요.
주간 청크의 예와 하루에 대한 데이터만 요청하는 쿼리를 다시 생각해 보세요. 타임스탬프 인덱스가 있는 일반 테이블에서 쿼리는 이 인덱스를 효율적으로 탐색하여 해당 날짜의 데이터를 찾을 수 있습니다.
그러나 압축된 데이터의 경우 상황이 다릅니다. 타임스탬프는 압축되어 전체 배치의 압축을 풀지 않으면 액세스할 수 없습니다. 각 개별 타임스탬프에 인덱스를 생성하는 것은 지나치게 커져서 압축의 이점을 무효화할 수 있으므로 비생산적입니다.
Timescale은 기본적으로 타임스탬프에 따라 일괄 처리할 데이터를 "정렬"하여 이 문제를 해결합니다. 그런 다음 각 배치의 최소 및 최대 타임스탬프에 대한 메타데이터를 기록합니다. 쿼리가 실행될 때 이 메타데이터를 통해 쿼리 엔진은 쿼리 시간 범위와 관련된 압축된 행(배치)을 신속하게 식별할 수 있으므로 전체 압축 해제의 필요성이 줄어듭니다.
이 방법은 세그먼트별 열을 사용하여 효과적으로 작동합니다. 압축 프로세스 중에 데이터는 먼저 세그먼트별 열을 기준으로 그룹화된 다음 orderby 매개변수를 기준으로 정렬된 다음 마지막으로 각각 최대 1,000개의 행을 포함하는 더 작은 타임스탬프 정렬 "미니 배치"로 나뉩니다.
TimescaleDB의 분할과 정렬을 결합하면 일반적인 시계열 및 분석 쿼리의 성능이 크게 향상됩니다. 시간( orderby
통해)과 공간( segmentby
통해)에 대한 이러한 최적화는 TimescaleDB가 대규모 시계열 데이터를 효과적으로 관리하고 쿼리하여 압축과 접근성 간의 최적화된 균형을 제공하도록 보장합니다.
압축 설계의 첫 번째 버전은 2019년 TimescaleDB 1.5 와 함께 출시되었습니다. 이후 많은 릴리스에서 Timescale 압축은 큰 발전을 이루었습니다.
초기 릴리스의 주요 제한 사항 중 하나는 데이터가 압축된 후에는 해당 데이터가 있는 전체 하이퍼테이블 청크의 압축을 먼저 수동으로 풀지 않고는 데이터의 추가 수정(예: INSERT, UPDATE, DELETE)을 허용하지 않았다는 것입니다.
주로 삽입이 많고 업데이트가 많지 않은 분석 및 시계열 데이터를 기반으로 하는 데이터 집약적 사용 사례에 맞게 최적화하고 있다는 점을 고려하면 이는 기존 OLTP 사용 사례에 비해 제한이 훨씬 적습니다. 데이터가 자주 업데이트되는 경우(예: 고객 정보 테이블) 하지만,
초기 압축 릴리스의 또 다른 제한 사항은 압축 데이터를 포함하여 테이블의 스키마 수정을 허용하지 않았다는 것입니다. 이는 개발자가 전체 테이블의 압축을 풀지 않고는 데이터 구조를 발전시킬 수 없다는 것을 의미했습니다.
오늘날 이러한 제한 사항은 모두 제거되었습니다. 이제 Timescale을 사용하면 압축된 데이터에 대해 전체 DML(데이터 조작 언어) 및 DDL(데이터 정의 언어) 작업을 수행할 수 있습니다.
UPDATE, UPSERT 및 DELETE를 수행할 수 있습니다.
기본값을 포함하여 열을 추가할 수 있습니다.
열 이름을 바꾸고 삭제할 수 있습니다.
압축된 데이터에 대한 데이터 수정을 자동화하기 위해(사용자가 원활하게 수행할 수 있도록) "스테이징 영역"을 도입하여 압축 접근 방식을 변경했습니다. 기본적으로 압축되지 않은 상태로 유지되고 "압축되지 않은 데이터에 대해" 작업을 수행하는 중첩 청크입니다. 후드.
사용자로서 귀하는 수동으로 아무것도 할 필요가 없습니다. 우리 엔진이 모든 것을 자동으로 처리하는 동안 데이터를 직접 수정할 수 있습니다. 압축된 데이터를 변경하는 기능은 Timescale의 하이브리드 행-열 스토리지 엔진을 훨씬 더 유연하게 만듭니다.
스테이징 영역을 통한 이 디자인은 INSERT를 압축되지 않은 청크에 삽입하는 것만큼 빠르게 만듭니다. 왜냐하면 이것이 실제로 일어나고 있기 때문입니다(압축된 청크에 삽입하면 이제 스테이징 영역에 기록됩니다). 또한 UPDATE, UPSERT 및 DELETE를 직접 지원할 수 있었습니다. 값을 변경해야 할 경우 엔진은 압축된 데이터의 관련 부분을 스테이징 영역으로 이동하고 압축을 풀고 변경을 수행한 다음 (비동기적으로) 다시 이동합니다. 압축된 형식으로 기본 테이블에 추가됩니다.
(이 데이터 영역은 일반적으로 수정을 지원하기 위해 압축을 풀어야 하는 데이터의 양을 최소화하기 위해 기본 PostgreSQL 스토리지의 "행"을 구성하는 최대 1,000개 값의 압축된 "미니 배치" 규모로 작동합니다.)
이 "스테이징 영역"에는 여전히 일반적인 트랜잭션 의미가 있으며 쿼리에 값이 삽입되자마자 해당 값이 표시됩니다. 즉, 쿼리 플래너는 이러한 행 기반 "스테이징" 청크와 일반 열 형식 스토리지에 걸쳐 적절하게 쿼리하는 방법을 이해할 만큼 똑똑합니다.
이 시점에서 다음으로 물어볼 논리적 질문은 최종 결과는 무엇입니까?입니다. 압축은 쿼리 성능에 어떤 영향을 미치며, 압축을 사용하면 디스크 크기를 얼마나 절약할 수 있나요?
이 문서에서 논의한 것처럼 열 형식 저장소는 일반적으로 개별 행을 검색하는 쿼리에는 적합하지 않지만 집계된 값을 보는 분석 쿼리에는 훨씬 더 나은 성능을 발휘하는 경향이 있습니다. 이것이 바로 Timescale에서 볼 수 있는 것입니다. 평균과 관련된 깊고 좁은 쿼리는 압축을 사용할 때 상당한 성능 향상을 보여줍니다.
이에 대해 몇 가지 쿼리를 실행하여 설명하겠습니다.
특정 기간 내에 택시 데이터 세트의 하위 집합에서 가장 높은 요금을 요청하는 다음 쿼리를 고려해 보세요.
SELECT max(fare_amount) FROM demo.yellow_compressed_ht WHERE tpep_pickup_datetime >= '2019-09-01' AND tpep_pickup_datetime <= '2019-12-01';
압축되지 않은 데이터 세트에 대해 실행하면 쿼리 실행 시간은 4.7초입니다. 우리는 소규모의 최적화되지 않은 테스트 서비스를 사용하고 수백만 개의 행을 쿼리하고 있으므로 이 성능은 최고가 아닙니다. 그러나 데이터를 압축한 후에는 응답 시간이 77.074밀리초로 낮아집니다.
또 다른 예를 공유해 보겠습니다. 이 쿼리는 지정된 기간 내에 특정 요금 코드를 사용하는 이동 횟수를 계산합니다.
SELECT COUNT(*) FROM demo.yellow_compressed_ht WHERE tpep_pickup_datetime >= '2019-09-01' AND tpep_pickup_datetime <= '2019-12-01' AND "RatecodeID" = 99;
압축되지 않은 데이터에 대해 실행될 경우 이 쿼리를 완료하는 데 1.6초가 걸립니다. 압축된 데이터에 대해 실행되는 동일한 쿼리는 단 18.953밀리초 만에 완료됩니다. 다시 한 번 즉각적인 개선이 이루어졌습니다! 이는 단지 간단한 예일 뿐이지만 쿼리 속도를 높이는 데 압축이 얼마나 강력한지 보여줍니다.
애초에 여기까지 온 이유를 잊지 마십시오. PostgreSQL을 더욱 확장할 수 있도록 대규모 PostgreSQL 데이터베이스의 크기를 줄일 수 있는 전술이 필요했습니다. 이 작업에 Timescale 압축이 얼마나 효과적인지 보여주기 위해 아래 표 에는 Timescale 고객 사이에서 볼 수 있는 압축 비율의 실제 예가 포함되어 있습니다.
이러한 스토리지 절감은 바로 비용 절감으로 이어집니다.
궁극적으로 달성할 압축률은 데이터 유형 및 액세스 패턴을 포함한 여러 요소에 따라 달라집니다. 하지만 보시다시피 시간 단위 압축은 매우 효율적일 수 있습니다.
우리 팀은 가능한 한 많은 비용을 절약할 수 있도록 압축을 미세 조정하는 데 도움을 드릴 수 있습니다.
"압축을 통해 [디스크 크기]가 평균 97% 감소했습니다."
(마이클 갈리아르도, 산업)
“우리는 Timescale의 압축 비율이 정말 놀랍다는 것을 발견했습니다! 현재 압축률은 26이 넘고, 모든 데이터를 저장하는 데 필요한 디스크 공간이 크게 줄어듭니다."
(니콜라스 퀸틴, 옥타브)
"Timescale의 압축은 광고한 것만큼 훌륭하여 기본 하이퍼테이블에서 [디스크] 공간을 90% 이상 절약했습니다."
(파올로 베르간티노, METER 그룹)
마지막으로 Timescale의 계층형 스토리지에 대한 언급을 빼놓고는 이 기사를 마무리할 수 없었습니다.
압축 외에도 이제 Timescale 플랫폼에서 PostgreSQL 데이터베이스를 더욱 확장하는 데 도움이 되는 또 다른 도구가 있습니다. 오래되고 자주 액세스하지 않는 데이터를 저렴한 개체 스토리지 계층으로 계층화하는 동시에 표준을 통해 계속 액세스할 수 있습니다. SQL.
이 저렴한 스토리지 계층은 GB당 월 $0.021의 데이터 요금으로 Amazon S3보다 저렴하므로 적은 비용으로 PostgreSQL 데이터베이스에 많은 TB를 유지할 수 있습니다.
이는 계층형 스토리지 백엔드가 Timescale 플랫폼에서 작동하는 방식과 낮은 스토리지 계층이 압축과 함께 작동하는 방식입니다.
최신 데이터는 빠른 쿼리와 높은 수집에 최적화된 고성능 스토리지 계층 에 기록됩니다. 이 계층에서는 이 문서에서 설명한 대로 시간 척도 열 형식 압축을 활성화하여 데이터베이스 크기를 줄이고 분석 쿼리 속도를 높일 수 있습니다. 예를 들어 1주일 후에 데이터를 압축하는 압축 정책을 정의할 수 있습니다.
애플리케이션이 더 이상 해당 데이터에 자주 액세스하지 않으면 계층화 정책을 설정하여 자동으로 이를 저렴한 개체 스토리지 계층 으로 계층화할 수 있습니다. 저렴한 스토리지 계층의 데이터는 데이터베이스 내에서 완전히 쿼리 가능한 상태로 유지되며 저장할 수 있는 데이터 양에는 제한이 없습니다(최대 수백 TB 이상). 예를 들어 6개월이 지난 모든 데이터를 저렴한 스토리지 계층으로 이동하는 계층화 정책을 정의할 수 있습니다.
이 데이터를 더 이상 데이터베이스에 보관할 필요가 없으면 보존 정책을 통해 해당 데이터를 삭제할 수 있습니다. 예를 들어 5년 후에는 모든 데이터를 삭제할 수 있습니다.
우리는 컬럼 압축 기능을 추가하여 Postgres에 효과적인 데이터베이스 압축 메커니즘을 제공했습니다. 이는 오늘날 데이터 집약적인 세계에서 PostgreSQL 데이터베이스를 확장하는 데 필수적인 기능입니다. 압축을 사용하면 디스크 사용량(더 저렴하게 더 많은 데이터 저장)을 크게 절약하고 성능을 향상(밀리초 단위로 대용량에 대한 분석 쿼리 실행)할 수 있습니다.
Timescale의 압축 설계는 PostgreSQL 내에서 하이브리드 행/열 스토리지를 생성하는 새로운 방법과 함께 동급 최고의 압축 알고리즘을 결합하여 인상적인 압축 속도를 달성합니다. 이 기능을 통해 Timescale(및 PostgreSQL)의 스토리지 공간은 맞춤형으로 구축된 더욱 제한적인 열 기반 데이터베이스와 동등해졌습니다.
그러나 많은 열 형식 엔진과 달리 Timescale은 ACID 트랜잭션 의미 체계를 지원하고 압축된 열 형식 데이터에 대한 수정(INSERT, UPDATE, UPSERT, DELETE)을 직접 지원합니다. "트랜잭션 워크로드용 데이터베이스 하나, 분석용 데이터베이스 하나"라는 기존 모델은 더 이상 사용되지 않기 때문에 많은 최신 애플리케이션은 두 패턴 모두에 맞는 워크로드를 실행합니다. 그렇다면 PostgreSQL에서 모든 작업을 수행할 수 있는데 왜 두 개의 별도 데이터베이스를 유지해야 할까요?
Timescale을 사용하면 PostgreSQL에서 시작하고, PostgreSQL로 확장하고, PostgreSQL을 유지할 수 있습니다.
- Carlota Soto와 Mike Freedman 이 작성함.
여기에도 게시되었습니다 .