수십억 행 테이블에 대한 느린 쿼리 // 사용 된 인덱스


10

나는 젊은 개발자이고 데이터베이스 사용에 실제로 숙련되지 않았기 때문에 (PostgreSQL 9.3) 프로젝트에 문제가 발생하여 실제로 도움이 필요합니다.

내 프로젝트는 모든 장치가 초당 하나의 데이터 블록을 보내는 장치 (최대 1000 개 이상의 장치)에서 데이터를 수집하는 것입니다. 이는 시간당 약 3 백만 행을 만듭니다.

현재 모든 장치의 수신 데이터를 저장하는 하나의 큰 테이블이 있습니다.

CREATE TABLE data_block(
    id bigserial
    timestamp timestamp
    mac bigint
)

데이터 블록에 포함 할 수 있거나 포함 할 수없는 여러 유형의 데이터가 있기 때문에 테이블을 참조하는 다른 테이블이 data_block있습니다.

CREATE TABLE dataA(
    data_block_id bigserial
    data

    CONSTRAINT fkey FOREIGN KEY (data_block_id) REFERENCES data_block(id);
);
CREATE TABLE dataB(...);
CREATE TABLE dataC(...);
CREATE INDEX index_dataA_block_id ON dataA (data_block_id DESC);
...

하나의 data_block에는 3x dataA, 1x dataB가 있지만 dataC는 없을 수 있습니다.

데이터는 몇 주 동안 유지 되므로이 표에 ~ 50 억 행이 있습니다. 현재 테이블에 ~ 6 억 행이 있으며 쿼리에 시간이 오래 걸립니다. 그래서 select 문은 항상 시간이 지남에 따라 쿼리되고 종종 시간이 지남에 따라 쿼리되기 때문에 timestamp및에 인덱스를 만들기로 결정했습니다 mac.

CREATE INDEX index_ts_mac ON data_block (timestamp DESC, mac);

...하지만 내 쿼리는 여전히 오래 걸립니다. 예를 들어, 하루 동안 데이터와 하나의 맥을 쿼리했습니다.

SELECT * FROM data_block 
WHERE timestamp>'2014-09-15' 
AND timestamp<'2014-09-17' 
AND mac=123456789
Index Scan using index_ts_mac on data_block  (cost=0.57..957307.24 rows=315409 width=32) (actual time=39.849..334534.972 rows=285857 loops=1)
  Index Cond: ((timestamp > '2014-09-14 00:00:00'::timestamp without time zone) AND (timestamp < '2014-09-16 00:00:00'::timestamp without time zone) AND (mac = 123456789))
Total runtime: 334642.078 ms

쿼리 실행 전에 완전히 진공 청소기로 청소했습니다. <10sec 미만의 쿼리를 수행하기 위해 큰 테이블로 이러한 문제를 해결하는 우아한 방법이 있습니까?

파티셔닝에 대해 읽었지만 data_block_id에 대한 dataA, dataB, dataC 참조에서 작동하지 않습니다. 어떻게 든 작동한다면 시간이 지남에 따라 또는 Mac을 통해 파티션을 만들어야합니까?

색인을 다른 방향으로 변경했습니다. 먼저 MAC, 타임 스탬프 및 많은 성능을 얻습니다.

CREATE INDEX index_mac_ts ON data_block (mac, timestamp DESC);

그러나 여전히 쿼리는 30 초 이상 걸립니다. 특히 LEFT JOIN데이터 테이블로 작업 할 때 . 다음은 EXPLAIN ANALYZE새로운 색인을 사용한 쿼리입니다.

EXPLAIN ANALYZE SELECT * FROM data_block WHERE mac = 123456789 AND timestamp < '2014-10-05 00:00:00' AND timestamp > '2014-10-04 00:00:00'
Bitmap Heap Scan on data_block  (cost=1514.57..89137.07 rows=58667 width=28) (actual time=2420.842..32353.678 rows=51342 loops=1)
  Recheck Cond: ((mac = 123456789) AND (timestamp < '2014-10-05 00:00:00'::timestamp without time zone) AND (timestamp > '2014-10-04 00:00:00'::timestamp without time zone))
  ->  Bitmap Index Scan on index_mac_ts  (cost=0.00..1499.90 rows=58667 width=0) (actual time=2399.291..2399.291 rows=51342 loops=1)
        Index Cond: ((mac = 123456789) AND (timestamp < '2014-10-05 00:00:00'::timestamp without time zone) AND (timestamp > '2014-10-04 00:00:00'::timestamp without time zone))
Total runtime: 32360.620 ms 

불행히도 내 하드웨어는 엄격히 제한되어 있습니다. Intel i3-2100 @ 3.10Ghz, 4GB RAM을 사용하고 있습니다. 현재 설정은 다음과 같습니다.

default_statistics_target = 100
maintenance_work_mem = 512MB
constraint_exclusion = on
checkpoint_completion_target = 0.9
effective_cache_size = 4GB
work_mem = 512MB
wal_buffers = 16MB
checkpoint_segments = 32
shared_buffers = 2GB
max_connections = 20
random_page_cost = 2

답변:


1

이것은 내 MS SQL 편견을 반영 할 수 있지만에 의해 테이블을 클러스터링하려고합니다 timestamp. 특정 기간 동안 데이터를 자주 가져 오는 경우 데이터가 물리적으로 연속적으로 저장되므로 도움이됩니다. 시스템은 시작점을 찾고 범위의 끝까지 스캔하여 완료 할 수 있습니다. 특정 시간을 쿼리하는 경우 3,600,000 개의 레코드에 불과합니다.

특정 머신에 대한 쿼리 (...?) 인 경우 Postgres는 3.6 M 레코드의 99.9 %를 필터링해야합니다. 이 일대일 필터가 일반적인 날짜 범위 피팅보다 선택적인 경우 mac인덱스의 첫 번째 구성 요소로 더 선택적인 필드를 사용해야합니다 . 여전히 클러스터링 할 가치가 있습니다.

그래도 그렇게하지 않으면 색인을 생성하는 동일한 필드 timestamp또는로 분할합니다 mac.

데이터 유형을 제공하지 않았습니다. 데이터에 적합합니까? 예를 들어, 날짜를 텍스트로 저장하면 테이블이 불필요하게 부 풀릴 수 있습니다.


2
포스트 그레스는 인덱스를 클러스터하지 않습니다 (이 수 있지만 클러스터 인덱스를 따라 테이블을 -하지만 요구는 수동으로 수행 할을하지 않습니다 "숙박")
a_horse_with_no_name

조언 감사합니다. 이제 이전보다 빠르게 실행되지만 쿼리 당 30 초 이상 매우 낮은 성능을 유지합니다. 나는 또한 클러스터링을했지만 @a_horse_with_no_name이 말했듯이 postgres에서 이것은 원샷입니다. 내 데이터 형식이 옳다고 생각합니다. 나는 질문에 추가했다
manman

클러스터 된 테이블이 없으면 범위 쿼리에 대한 다음 권장 사항은 파티셔닝입니다.
모든 거래의 존

-2

전기 계량기에서 수십억 건의 판독 값을 가진 응용 프로그램을 작업했으며 10 초 이내에 대부분의 쿼리를 실행했습니다.

우리의 환경은 달랐습니다. 서버 클래스 시스템의 Microsoft SQL Server (4 코어, 24GB 메모리) 서버로 업그레이드 할 기회가 있습니까?

한 가지 큰 문제는 한 번에 하나씩 판독 값을 수집하면 데이터베이스에 큰 성능 영향을 미친다는 것입니다. 데이터를 작성하려면 잠금 및 쿼리가 필요합니다. 일괄 삽입을 할 수 있습니까?

스키마를 사용하면 4 개의 매우 큰 테이블이 있습니다. 모든 조인이 두 테이블 모두에서 인덱스를 사용하는 것이 중요합니다. 테이블 스캔에는 시간이 오래 걸립니다. 널 (null) 필드가있는 1 개의 테이블로 병합 할 수 있습니까?


일괄 삽입 : 대량 삽입을 할 수는 있지만 지금은 쿼리가 실행되는 동안 삽입이 전혀없는 테스트 데이터베이스에서 작업하고 있습니다. 그러나 고맙습니다. 나중에 생각할 것입니다 :) 인덱스 : 나는 모든 테이블에 인덱스가 있습니다. 데이터 테이블에서 ID의 인덱스, data_block 테이블의 (mac, 타임 스탬프). 왼쪽 조인 당 dataA를 검색 할 때도 문제가 있지만 그렇지 않습니다. 인덱스를 사용하더라도 데이터 테이블을 검색합니다. null_able fields : data_block은 한 종류 이상의 데이터를 가질 수 있기 때문에 불가능합니다. 1xdata_block-> 4xdataA 예
manman

DB 도구가 쿼리 분석기를 제공합니까? id를 기준으로 data_block에 대한 색인이 필요할 수 있습니다.
KC-NH

나는 노력할 것이다, 그러나 이것이 왜 도움이 될 수 있는지 이해하지 못한다!?
manman

-2

Postgres (또는 다른 RDBMS)의 고유 한 확장 성 한계에 도달했습니다.

RDBMS 인덱스는 B- 트리입니다. B- 트리는 평균과 최악의 경우 모두 O (log n)입니다. 이것은 합리적인 N 값에 대해 훌륭하고 안전하며 예측 가능한 선택입니다. N이 너무 커지면 고장납니다.

NoSQL 데이터베이스는 (대부분) 해시 테이블입니다. 해시 테이블은 평균 경우 O (1)이고 최악의 경우 O (n)입니다. 최악의 경우를 피할 수 있다고 가정하면 매우 큰 N 값에 대해 실제로 잘 수행됩니다.

또한 해시 테이블은 병렬화가 쉽고 b- 트리는 그렇지 않습니다. 따라서 해시 테이블이 분산 컴퓨팅 아키텍처에 더 적합합니다.

수십억 개의 행 테이블을 얻기 시작하면 RDBMS에서 NoSQL로 전환하는 것을 고려해야합니다. 카산드라는 아마도 당신의 유스 케이스에 좋은 선택 일 것입니다.


2
많은 RDBMS에는 B- 트리 인덱스 (해시, 비트 맵 등)보다 더 많은 옵션이 있습니다. 일부 DBMS는 행을 저장하고 일부는 열을 저장합니다. 그리고 O (logn)는 수십억 행에 대해서도 나쁘지 않습니다. 그리고 그들은 4GB 메모리 머신을 사용할 때 어떤 한계에 부딪 칠 수 없습니다.
ypercubeᵀᴹ
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.