Effizientes Zusammenführen (Entfernen von Duplikaten) von Arrays


10

Ich habe zwei Tische left2und right2. Beide Tabellen sind groß (1-10 Millionen Zeilen).

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

Ich werde diese Art von Abfrage durchführen:

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;

Wo ich für die Aggregation von Arrays die Funktion benutze:

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

Nach dem Verketten der Arrays verwende ich die UNIQFunktion des intarrayModuls. Gibt es eine effizientere Möglichkeit, dies zu tun? Gibt es einen Index für das arrFeld, um das Zusammenführen zu beschleunigen (mit dem Entfernen von Duplikaten)? Kann die Aggregatfunktion Duplikate direkt entfernen? Original-Arrays können als sortiert betrachtet werden (und sie sind eindeutig), wenn dies hilfreich ist.

Die SQL-Geige ist hier :


Werden Sie Millionen von Zeilen gleichzeitig abfragen? Was machst du mit dem Ergebnis? Oder wird es Prädikate geben, um einige auszuwählen? Kann right2.arr NULL sein, wie es Ihr Demo-Schema vorschlägt? Benötigen Sie als Ergebnis sortierte Arrays?
Erwin Brandstetter

Antworten:


9

Richtige Ergebnisse?

Zunächst einmal: Korrektheit. Sie möchten eine Reihe einzigartiger Elemente erstellen? Ihre aktuelle Abfrage macht das nicht. Die Funktion uniq()des Intarray- Moduls verspricht nur:

benachbarte Duplikate entfernen

Wie im Handbuch beschrieben , benötigen Sie:

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

Gibt Ihnen auch sortierte Arrays - vorausgesetzt, Sie möchten das, haben Sie nicht geklärt.

Ich sehe, Sie haben sort() in Ihrer Geige , also kann dies nur ein Tippfehler in Ihrer Frage sein.

Postgres 9.5

In jedem Fall werden Sie den neuen Postgres 9.5 (derzeit Beta) lieben . Es bietet die Funktionen von array_agg_mult()sofort einsatzbereit und viel schneller:

Es gab auch andere Leistungsverbesserungen für die Array-Handhabung.

Abfrage

Der Hauptzweck von array_agg_mult()besteht darin, mehrdimensionale Arrays zu aggregieren, aber Sie erzeugen sowieso nur eindimensionale Arrays. Also würde ich zumindest diese alternative Abfrage versuchen:

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;

Welches auch Ihre Frage anspricht:

Kann die Aggregatfunktion Duplikate direkt entfernen?

Ja, das kann es mit DISTINCT. Dies ist jedoch nicht schneller als uniq()bei Integer-Arrays, die für Integer-Arrays optimiert wurden, während sie DISTINCTfür alle qualifizierenden Datentypen generisch sind.

Benötigt das intarrayModul nicht. Das Ergebnis ist jedoch nicht unbedingt sortiert. Postgres verwendet unterschiedliche Algorithmen für DISTINCT(IIRC). Große Mengen werden normalerweise gehasht. Das Ergebnis wird nur sortiert, wenn Sie explizit hinzufügen ORDER BY. Wenn Sie sortierten Arrays benötigen, Sie könnten hinzufügen , ORDER BYdirekt auf die Aggregatfunktion:

array_agg(DISTINCT elem ORDER BY elem)

Dies ist jedoch in der Regel langsamer als das Zuführen vorsortierter Daten array_agg()(eine große Sortierung gegenüber vielen kleinen Sortierungen). Also würde ich in einer Unterabfrage sortieren und dann aggregieren:

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;

Dies war die schnellste Variante in meinem flüchtigen Test auf Postgres 9.4.

SQL Fiddle basierend auf dem von Ihnen angegebenen.

Index

Ich sehe hier nicht viel Potenzial für einen Index. Die einzige Option wäre:

CREATE INDEX ON right2 (t1, arr);

Dies ist nur dann sinnvoll, wenn Sie nur Index-Scans erhalten. Dies ist der Fall, wenn die zugrunde liegende Tabelle right2wesentlich breiter als nur diese beiden Spalten ist und Ihr Setup für Nur-Index-Scans qualifiziert ist. Details im Postgres Wiki.


Danke +1. Ich muss später sowieso UNNEST, möchte aber überprüfen, ob Duplikate in den Arrays entfernt werden, und dann ist UNNEST schneller.
Alexandros

0

Ich bin wirklich enttäuscht, dies ist in Microsoft Access ganz einfach. Sie können eine Abfrage zum Entfernen von Duplikaten erstellen und dann in SQL nachsehen, wie dies funktioniert. Ich muss einen Windows-Computer starten, um zu schauen. Sie variieren, der Abfrage-Assistent macht es.

Eine Sache, die meiner Meinung nach funktioniert, ist, alle Ihre Daten in eine Tabelle zu laden und dann SELECT DISTINCT in eine neue Tabelle auszuführen. Sie können auch eine Order-by-Klausel einhalten, während Sie gerade dabei sind. Ich habe es vor einem Jahr irgendwie gemacht, das muss es sein.

Ich kombiniere Temperaturdaten im Wert von 2 Jahren. Der Sensor sendet jede Minute 2 Kopien desselben Datenpunkts als redundanten Schutz. Manchmal wird man verwüstet, aber ich möchte nur einen behalten. Ich habe auch Überlappungen zwischen Dateien.

Wenn die Daten während des gesamten Laufs genau das gleiche Format haben, können Sie auf einem Unix-Computer so etwas tun

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

Aber uniq vergleicht Zeilen als Zeichenfolgen und zum Beispiel ist 18.7000 nicht dasselbe wie 18.7. Ich habe meine Software in den 2 Jahren geändert, sodass ich beide Formate habe.


Von Postgres enttäuscht? Hat Access überhaupt Arrays?
Ypercubeᵀᴹ

Ich weiß es nicht, aber es kann Duplikate entfernen. Es ist ein häufig genug auftretendes Problem bei der Datenbereinigung. Wählen Sie deutlich ist nah genug. Sie haben nicht immer die Kontrolle über Ihre Rohdaten aus der realen Welt.
Alan Corey
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.