J'ai deux tables, left2
et right2
. Les deux tables seront grandes (1 à 10 millions de lignes).
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);
Je vais effectuer ce type de requête:
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;
Où pour l'agrégation de tableaux, j'utilise la fonction:
CREATE AGGREGATE array_agg_mult(anyarray) (
SFUNC=array_cat,
STYPE=anyarray,
INITCOND='{}');
Après avoir concaténé les tableaux, j'utilise la fonction UNIQ
du module intarray
. Existe-t-il un moyen plus efficace de procéder? Existe-t-il un index sur le champ arr
pour accélérer la fusion (avec suppression des doublons)? La fonction d'agrégation peut-elle supprimer directement les doublons? Les tableaux originaux peuvent être considérés comme triés (et ils sont uniques) si cela aide.
Le SQL Fiddle is here :
Tout d'abord: l'exactitude. Vous souhaitez produire un tableau d'éléments uniques? Votre requête actuelle ne fait pas cela. La fonction uniq()
du module intarray ne promet que:
supprimer les doublons adjacents
Comme indiqué dans le manuel , vous auriez besoin de:
SELECT l.d + r.d, uniq(sort(array_agg_mult(r.arr)))
FROM ...
Vous donne également trié tableaux - en supposant que vous le vouliez, vous n'avez pas clarifié.
Je vous vois ayezsort()
dans votre violon , donc cela peut être juste une faute de frappe dans votre question.
Quoi qu'il en soit, vous allez - aimer le nouveau Postgres 9.5 (actuellement en version bêta). Il fournit les capacités de array_agg_mult()
hors de la boîte et beaucoup plus rapide:
Il y a également eu d'autres améliorations de performances pour la gestion des baies.
Le but principal de array_agg_mult()
est d'agréger des tableaux multidimensionnels, mais vous ne produisez de toute façon que des tableaux unidimensionnels. Je voudrais donc au moins essayer cette requête alternative:
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;
Ce qui répond également à votre question:
La fonction d'agrégation peut-elle supprimer directement les doublons?
Oui, c'est possible avec DISTINCT
. Mais ce n'est pas plus rapide que uniq()
pour les tableaux entiers, qui a été optimisé pour les tableaux entiers, tandis que DISTINCT
est générique pour tous les types de données éligibles.
Ne nécessite pas le module intarray
. Cependant , le résultat n'est pas nécessairement trié. Postgres utilise différents algorithmes pour DISTINCT
(IIRC), les grands ensembles sont généralement hachés, puis le résultat n'est pas trié sauf si vous ajoutez explicitement ORDER BY
. Si vous avez besoin de tableaux triés, vous pourriez ajouter directement ORDER BY
À la fonction d'agrégation:
array_agg(DISTINCT elem ORDER BY elem)
Mais c'est généralement plus lent que de fournir des données pré-triées à array_agg()
(un grand tri contre plusieurs petits). Donc je trierais dans une sous-requête et alors agrégerait:
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;
C'était la variante la plus rapide de mon test superficiel sur Postgres 9.4.
SQL Fiddle basé sur celui que vous avez fourni.
Je ne vois pas beaucoup de potentiel pour un indice ici. La seule option serait:
CREATE INDEX ON right2 (t1, arr);
Cela n'a de sens que si vous obtenez des analyses d'index uniquement - ce qui se produira si la table sous-jacente right2
Est nettement plus large que ces deux colonnes et que votre configuration est admissible à analyses d'index uniquement. Détails dans le wiki Postgres.
Je suis vraiment déçu, c'est une chose facile à faire dans Microsoft Access. Vous pouvez créer une requête "supprimer les doublons" puis regarder le SQL pour voir comment il le fait. Je vais devoir allumer une machine Windows pour regarder. Ils varient, l'assistant de requête le fait.
Une chose qui fonctionne, je pense, est de charger toutes vos données dans une table, puis de faire SELECT DISTINCT dans une nouvelle table. Vous pouvez également coller une clause de commande par ordre pendant que vous y êtes. Je l'ai fait il y a un an, ça doit être ça.
Je combine 2 années de données de température, le capteur envoie chaque minute 2 copies du même point de données comme sauvegarde redondante. Parfois, on est saccagé, mais je veux seulement en garder un. J'ai également des chevauchements entre les fichiers.
Si les données sont exactement au même format sur l'ensemble du cycle, sur une machine Unix, vous pouvez faire quelque chose comme
cat *.tab > points.txt
sort -n < points.txt > sorted.txt
uniq -u sorted.txt unique.txt
Mais uniq compare les lignes comme des chaînes et, par exemple, 18.7000 n'est pas identique à 18.7. J'ai changé de logiciel pendant 2 ans donc j'ai les deux formats.