Hợp nhất hiệu quả (loại bỏ trùng lặp) các mảng


10

Tôi có hai bảng, left2right2. Cả hai bảng sẽ lớn (1-10M hàng).

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);

Tôi sẽ thực hiện loại truy vấn này:

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;

Trường hợp tổng hợp các mảng tôi sử dụng hàm:

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

Sau khi nối các mảng, tôi sử dụng UNIQchức năng của intarraymô-đun. Có cách nào hiệu quả hơn để làm điều này? Có bất kỳ chỉ mục nào trên arrtrường để tăng tốc độ hợp nhất (với việc loại bỏ trùng lặp) không? Hàm tổng hợp có thể loại bỏ các bản sao trực tiếp không? Mảng gốc có thể được coi là sắp xếp (và chúng là duy nhất) nếu điều đó có ích.

Fiddle SQL ở đây :


Bạn sẽ truy vấn hàng triệu hàng cùng một lúc? Bạn đang làm gì với kết quả? Hoặc sẽ có những vị ngữ để chọn một vài? Có thể right2.arr là NULL như lược đồ demo của bạn gợi ý? Bạn có cần sắp xếp các mảng như kết quả?
Erwin Brandstetter

Câu trả lời:


9

Kết quả đúng?

Trước hết: tính đúng đắn. Bạn muốn sản xuất một loạt các yếu tố độc đáo? Truy vấn hiện tại của bạn không làm điều đó. Chức năng uniq()từ mô-đun intarray chỉ hứa hẹn:

loại bỏ các bản sao liền kề

Giống như được hướng dẫn trong hướng dẫn , bạn sẽ cần:

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

Cũng cung cấp cho bạn các mảng được sắp xếp - giả sử bạn muốn điều đó, bạn đã không làm rõ.

Tôi thấy bạn sort() trong câu đố của bạn , vì vậy đây có thể chỉ là một lỗi đánh máy trong câu hỏi của bạn.

Hậu 9,5

Dù bằng cách nào, bạn sẽ thích Postgres 9.5 mới (hiện đang là beta). Nó cung cấp các khả năng array_agg_mult()vượt trội và nhanh hơn nhiều:

Cũng đã có những cải tiến hiệu suất khác để xử lý mảng.

Truy vấn

Mục đích chính array_agg_mult()là tổng hợp các mảng đa chiều, nhưng dù sao bạn cũng chỉ tạo ra các mảng 1 chiều. Vì vậy, tôi ít nhất sẽ thử truy vấn thay thế này:

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;

Điều này cũng giải quyết câu hỏi của bạn:

Hàm tổng hợp có thể loại bỏ các bản sao trực tiếp không?

Vâng, nó có thể, với DISTINCT. Nhưng điều đó không nhanh hơn so uniq()với mảng số nguyên, đã được tối ưu hóa cho mảng số nguyên, trong khi đó DISTINCTlà chung cho tất cả các loại dữ liệu đủ điều kiện.

Không yêu cầu intarraymô-đun. Tuy nhiên , kết quả không nhất thiết phải được sắp xếp. Postgres sử dụng các thuật toán khác nhau cho DISTINCT(IIRC), các bộ lớn thường được băm, sau đó kết quả không được sắp xếp trừ khi bạn thêm tường minh ORDER BY. Nếu bạn cần các mảng được sắp xếp, bạn có thể thêm ORDER BYtrực tiếp vào hàm tổng hợp:

array_agg(DISTINCT elem ORDER BY elem)

Nhưng điều đó thường chậm hơn so với việc cung cấp dữ liệu được sắp xếp trước array_agg()(một loại lớn so với nhiều loại nhỏ). Vì vậy, tôi sẽ sắp xếp trong một truy vấn con và sau đó tổng hợp:

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;

Đây là biến thể nhanh nhất trong thử nghiệm chữ thảo của tôi trên Postgres 9.4.

SQL Fiddle dựa trên cái bạn cung cấp.

Mục lục

Tôi không thấy nhiều tiềm năng cho bất kỳ chỉ số nào ở đây. Tùy chọn duy nhất sẽ là:

CREATE INDEX ON right2 (t1, arr);

Chỉ có ý nghĩa nếu bạn nhận được quét chỉ mục từ điều này - điều này sẽ xảy ra nếu bảng bên dưới right2rộng hơn đáng kể so với chỉ hai cột này và thiết lập của bạn đủ điều kiện để quét chỉ mục. Chi tiết trong Wiki Postgres.


Cảm ơn +1. Dù sao tôi cũng sẽ phải UNNEST, nhưng muốn kiểm tra xem việc loại bỏ trùng lặp trong mảng và sau đó UNNEST có nhanh hơn không.
Alexandros

0

Tôi thực sự thất vọng, đây là một điều dễ dàng để làm trong Microsoft Access. Bạn có thể tạo một truy vấn "loại bỏ trùng lặp" sau đó nhìn vào SQL để xem cách nó thực hiện. Tôi sẽ phải kích hoạt một máy Windows để xem xét. Họ khác nhau, trình hướng dẫn truy vấn làm điều đó.

Một điều hoạt động tôi nghĩ là tải tất cả dữ liệu của bạn vào một bảng sau đó thực hiện CHỌN DISTINCT vào một bảng mới. Bạn cũng có thể theo thứ tự theo mệnh đề trong khi bạn đang ở đó. Tôi đã làm nó bằng cách nào đó một năm trước, đó phải là nó.

Tôi đang kết hợp dữ liệu nhiệt độ trong 2 năm, cảm biến sẽ gửi 2 bản sao của cùng một điểm dữ liệu mỗi phút dưới dạng bảo vệ dự phòng. Đôi khi một người bị vùi dập, nhưng tôi chỉ muốn giữ một người. Tôi cũng có sự chồng chéo giữa các tập tin.

Nếu dữ liệu có cùng định dạng trên toàn bộ hoạt động, trên máy unix, bạn có thể làm một cái gì đó như

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

Nhưng uniq so sánh các dòng là các chuỗi và ví dụ 18.7000 không giống như 18.7. Tôi đã thay đổi phần mềm của mình trong 2 năm vì vậy tôi có cả hai định dạng.


Thất vọng từ Postgres? Liệu Access thậm chí có mảng?
ypercubeᵀᴹ

Tôi không biết nhưng nó có thể loại bỏ các bản sao, đó là một vấn đề đủ phổ biến trong việc làm sạch dữ liệu. Chọn riêng biệt là đủ gần. Bạn không luôn có quyền kiểm soát dữ liệu thô của mình từ thế giới thực.
Alan Corey
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.