การรวมกันอย่างมีประสิทธิภาพ (ลบรายการที่ซ้ำกัน) ของอาร์เรย์


10

ฉันมีสองตารางและleft2 right2ตารางทั้งสองจะมีขนาดใหญ่ (แถว 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ฟิลด์เพื่อเร่งการรวม (โดยการลบรายการซ้ำ) หรือไม่ ฟังก์ชันการรวมสามารถลบรายการที่ซ้ำกันได้โดยตรงหรือไม่ อาเรย์ดั้งเดิมอาจถูกพิจารณาว่าเรียงลำดับแล้ว (และมันไม่ซ้ำกัน) หากมีประโยชน์

ซอ Fiddle อยู่ที่นี่ :


คุณจะทำการค้นหาหลายล้านแถวพร้อมกันหรือไม่ คุณทำอะไรกับผลลัพธ์ หรือจะมีเพรดิเคตเพื่อเลือกไม่กี่คน? สามารถright2.arr เป็นโมฆะเช่นคีมาสาธิตให้เห็นของคุณ? คุณต้องการอาร์เรย์ที่เรียงลำดับตามผลลัพธ์หรือไม่
Erwin Brandstetter

คำตอบ:


9

แก้ไขผลลัพธ์หรือไม่

ก่อนปิด: ความถูกต้อง คุณต้องการที่จะผลิตชุดขององค์ประกอบที่ไม่ซ้ำกัน? แบบสอบถามปัจจุบันของคุณไม่ได้ทำเช่นนั้น ฟังก์ชั่นuniq()จากโมดูลintarrayสัญญาว่า:

ลบรายการที่อยู่ติดกัน

เช่นเดียวกับคำแนะนำในคู่มือคุณจะต้อง:

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

นอกจากนี้ยังให้คุณเรียงลำดับ - สมมติว่าคุณต้องการที่คุณไม่ได้ชี้แจง

ฉันเห็นว่าคุณมี sort()ในซอของคุณดังนั้นนี่อาจเป็นข้อผิดพลาดในคำถามของคุณ

Postgres 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) 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 เพื่อดู ตัวช่วยสร้างคิวรีแตกต่างกันไป

สิ่งหนึ่งที่ทำงานได้ฉันคิดว่าการโหลดข้อมูลทั้งหมดของคุณลงในตารางเดียวจากนั้นเลือก DISTINCT ที่เลือกลงในตารางใหม่ นอกจากนี้คุณยังสามารถสั่งตามคำสั่งในขณะที่คุณอยู่ที่มัน ฉันทำมันเมื่อปีที่แล้วมันต้องเป็นอย่างนั้น

ฉันกำลังรวมข้อมูลอุณหภูมิ 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.