어레이의 효율적인 병합 (중복 제거)


10

나는 두 개의 테이블을 가지고 left2right2. 두 테이블이 모두 큽니다 (1-10M 행).

CREATE TABLE left2(id INTEGER, t1 INTEGER, d INTEGER);
ALTER TABLE left2 ADD PRIMARY KEY (id,t1);

CREATE TABLE right2( t1 INTEGER, d INTEGER, arr INTEGER[] );
ALTER TABLE right2 ADD PRIMARY KEY(t1,d);

이 유형의 쿼리를 수행합니다.

SELECT l.d + r.d,
       UNIQ(SORT((array_agg_mult(r.arr)))
FROM left2 l,
     right2 r
WHERE l.t1 = r.t1
GROUP BY l.d + r.d
ORDER BY l.d + r.d;

배열 집계 위치는 다음과 같습니다.

CREATE AGGREGATE array_agg_mult(anyarray) (
SFUNC=array_cat,
STYPE=anyarray,
INITCOND='{}');

배열을 연결 한 후 모듈 의 UNIQ기능을 사용합니다 intarray. 더 효율적인 방법이 있습니까? arr필드에 병합 속도를 높이기위한 인덱스가 있습니까 (중복 제거)? 집계 함수가 중복을 직접 제거 할 수 있습니까? 도움이된다면 원래 배열은 정렬 된 것으로 간주 될 수 있습니다 (독특합니다).

SQL Fiddle은 다음과 같습니다.


한 번에 수백만 행을 쿼리 하시겠습니까? 결과로 무엇을하고 있습니까? 아니면 몇 가지를 선택할 술어가 있습니까? right2.arr 데모 스키마가 제안한 것처럼 NULL 일 수 있습니까 ? 결과적으로 정렬 된 배열이 필요합니까?
Erwin Brandstetter

답변:


9

올바른 결과?

우선 : 정확성. 독특한 요소의 배열을 만들고 싶습니까? 현재 쿼리는 그렇게하지 않습니다. intarray 모듈 의 기능 uniq()은 다음을 약속합니다.

인접한 중복 제거

마찬가지로 설명서에 지시 , 당신은해야합니다 :

SELECT l.d + r.d, uniq(sort(array_agg_mult(r.arr)))
FROM   ...

또한 정렬 된 배열을 제공합니다. 원한다고 가정하면 명확하지 않습니다.

나는 당신 sort() 당신의 바이올린에 있는 것을 보았 으므로 이것은 당신의 질문에 오타 일 수 있습니다.

포스트그레스 9.5

어느 쪽이든, 당신은 새로운 Postgres 9.5 (현재 베타)를 좋아할 것 입니다. array_agg_mult()즉시 사용 가능한 기능을 제공 하며 훨씬 더 빠릅니다.

어레이 처리를위한 다른 성능 개선 사항도 있습니다.

질문

주요 목적은 array_agg_mult()다차원 배열을 집계하는 것이지만 어쨌든 1 차원 배열 만 생성합니다. 그래서 나는 적어도이 대안 쿼리를 시도 할 것입니다 :

SELECT l.d + r.d AS d_sum, array_agg(DISTINCT elem) AS result_arr
FROM   left2  l
JOIN   right2 r USING (t1)
     , unnest(r.arr) elem
GROUP  BY 1
ORDER  BY 1;

또한 귀하의 질문을 해결합니다.

집계 함수가 중복을 직접 제거 할 수 있습니까?

그렇습니다 DISTINCT. 그러나 uniq()정수 배열에 대해 최적화 된 정수 배열 보다 빠르지는 않지만 DISTINCT모든 적격 데이터 유형에 일반적입니다.

intarray모듈이 필요하지 않습니다 . 그러나 결과가 반드시 정렬되지는 않습니다. Postgres는 DISTINCT(IIRC)에 대해 다양한 알고리즘을 사용 하고 큰 세트는 일반적으로 해시 된 다음 explicit 추가하지 않으면 결과가 정렬되지 않습니다 ORDER BY. 정렬 된 배열이 필요한 경우 집계 함수에 직접 추가 할 있습니다 ORDER BY.

array_agg(DISTINCT elem ORDER BY elem)

그러나 일반적으로 사전 정렬 된 데이터를 하나의 큰 정렬 대 많은 작은 정렬에 공급하는 것보다 느립니다array_agg() . 따라서 하위 쿼리를 정렬 한 다음 집계합니다.

SELECT d_sum, uniq(array_agg(elem)) AS result_arr
FROM  (
   SELECT l.d + r.d AS d_sum, elem
   FROM   left2  l
   JOIN   right2 r USING (t1)
        , unnest(r.arr) elem
   ORDER  BY 1, 2
   ) sub
GROUP  BY 1
ORDER  BY 1;

이것은 Postgres 9.4의 커서 테스트에서 가장 빠른 변형이었습니다.

제공 한 것을 기반으로하는 SQL Fiddle .

인덱스

나는 여기에 어떤 인덱스에 대한 많은 잠재력을 보지 못한다. 유일한 옵션은 다음과 같습니다.

CREATE INDEX ON right2 (t1, arr);

이 중에서 인덱스 전용 스캔을 얻는 경우에만 의미가 있습니다. 기본 테이블 right2이이 두 열보다 실질적으로 넓고 설정이 인덱스 전용 스캔에 적합한 경우에 발생합니다. Postgres Wiki의 세부 사항.


감사합니다 +1. 어쨌든 나중에 UNNEST해야하지만 배열에서 중복을 제거하고 UNNEST가 더 빠른지 확인하고 싶습니다.
Alexandros

0

정말 실망했습니다. 이것은 Microsoft Access에서 수행하기 쉬운 작업입니다. "중복 제거"쿼리를 만든 다음 SQL을보고 어떻게 수행되는지 확인할 수 있습니다. 보려고 Windows 머신을 작동시켜야합니다. 이들은 쿼리 마법사가 수행하는 방식에 따라 다릅니다.

작동하는 한 가지 방법은 모든 데이터를 하나의 테이블에로드 한 다음 SELECT DISTINCT를 새 테이블에 수행하는 것입니다. 당신이 그것을하고있는 동안 당신은 순서로 조항에 충실 할 수 있습니다. 나는 1 년 전에 그것을 어떻게했는지, 그것이되어야합니다.

2 년 분량의 온도 데이터를 결합하는이 센서는 매분마다 동일한 데이터 포인트의 사본 2 개를 중복 보호 장치로 보냅니다. 때때로 하나는 쓰레기이지만, 나는 단지 하나만 유지하고 싶습니다. 또한 파일이 겹칩니다.

전체 실행에서 데이터가 정확히 동일한 형식 인 경우, 유닉스 머신에서 다음과 같은 작업을 수행 할 수 있습니다

cat *.tab > points.txt
sort -n < points.txt > sorted.txt
uniq -u sorted.txt unique.txt

그러나 uniq은 행을 문자열로 비교하므로 18.7000은 18.7과 동일하지 않습니다. 2 년 동안 소프트웨어를 변경 했으므로 두 형식이 모두 있습니다.


Postgres에서 실망 했습니까? Access에도 배열이 있습니까?
ypercubeᵀᴹ

모르겠지만 중복을 제거 할 수 있습니다. 데이터 정리에서 일반적으로 충분한 문제입니다. 뚜렷한 선택이 충분합니다. 항상 실제 세계의 원시 데이터를 제어 할 수있는 것은 아닙니다.
Alan Corey
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.