Fusión eficiente (eliminación de duplicados) de matrices


10

Tengo dos mesas left2y right2. Ambas tablas serán grandes (de 1 a 10 millones de filas).

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

Realizaré este tipo de consulta:

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;

Donde para la agregación de matrices uso la función:

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

Después de concatenar las matrices, uso la UNIQfunción del intarraymódulo. ¿Hay una manera más eficiente de hacer esto? ¿Hay algún índice en el arrcampo para acelerar la fusión (con la eliminación de duplicados)? ¿Puede la función agregada eliminar duplicados directamente? Las matrices originales pueden considerarse ordenadas (y son únicas) si eso ayuda.

El Fiddle de SQL está aquí :


¿Vas a consultar millones de filas a la vez? ¿Qué haces con el resultado? ¿O habrá predicados para seleccionar algunos? ¿Puede right2.arr ser NULL como sugiere su esquema de demostración? ¿Necesita arreglos ordenados como resultado?
Erwin Brandstetter

Respuestas:


9

Resultados correctos?

Primero: corrección. ¿Quieres producir una variedad de elementos únicos? Su consulta actual no hace eso. La función uniq()del módulo intarray solo promete:

eliminar duplicados adyacentes

Como se indica en el manual , necesitaría:

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

También le da arreglos ordenados , suponiendo que quiera eso, no lo aclaró.

Veo que tienes sort() en tu violín , por lo que esto puede ser un error tipográfico en tu pregunta.

Postgres 9.5

De cualquier manera, te encantará el nuevo Postgres 9.5 (actualmente beta). Proporciona las capacidades array_agg_mult()listas para usar y mucho más rápido:

También ha habido otras mejoras de rendimiento para el manejo de matrices.

Consulta

El propósito principal de array_agg_mult()es agregar matrices multidimensionales, pero de todos modos solo se producen matrices unidimensionales. Entonces al menos probaría esta consulta alternativa:

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;

Lo que también aborda su pregunta:

¿Puede la función agregada eliminar duplicados directamente?

Sí, puede, con DISTINCT. Pero eso no es más rápido que uniq()para las matrices de enteros, que se ha optimizado para las matrices de enteros, mientras que DISTINCTes genérico para todos los tipos de datos que califican.

No requiere el intarraymódulo. Sin embargo , el resultado no está necesariamente ordenado. Postgres utiliza algoritmos variables para DISTINCT(IIRC), los conjuntos grandes generalmente se codifican, luego el resultado no se ordena a menos que agregue explícito ORDER BY. Si necesita matrices ordenadas, puede agregar ORDER BYdirectamente a la función de agregado:

array_agg(DISTINCT elem ORDER BY elem)

Pero eso suele ser más lento que alimentar datos previamente ordenados array_agg()(un tipo grande versus muchos tipos pequeños). Entonces ordenaría una subconsulta y luego agregaría:

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;

Esta fue la variante más rápida en mi prueba superficial en Postgres 9.4.

SQL Fiddle basado en el que proporcionó.

Índice

No veo mucho potencial para ningún índice aquí. La única opción sería:

CREATE INDEX ON right2 (t1, arr);

Solo tiene sentido si obtiene escaneos de solo índice de esto, lo que sucederá si la tabla subyacente right2es sustancialmente más ancha que solo estas dos columnas y su configuración califica para escaneos de solo índice. Detalles en el Wiki de Postgres.


Gracias +1. Tendré que DESNUDAR más tarde de todos modos, pero quiero verificar si eliminar duplicados en las matrices y luego DESNUDAR es más rápido.
Alexandros

0

Estoy realmente decepcionado, esto es algo fácil de hacer en Microsoft Access. Puede crear una consulta "eliminar duplicados" y luego mirar el SQL para ver cómo lo está haciendo. Tendré que encender una máquina Windows para buscar. Varían, el asistente de consultas lo hace.

Creo que una cosa que funciona es cargar todos sus datos en una tabla y luego hacer SELECT DISTINCT en una nueva tabla. También puede seguir un orden por cláusula mientras lo hace. Lo hice de alguna manera hace un año, eso debe ser.

Estoy combinando 2 años de datos de temperatura, el sensor envía 2 copias del mismo punto de datos cada minuto como protección redundante. A veces uno se destroza, pero solo quiero conservar uno. También tengo superposiciones entre archivos.

Si los datos tienen exactamente el mismo formato durante toda la ejecución, en una máquina Unix puede hacer algo como

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

Pero uniq compara líneas como cadenas y, por ejemplo, 18.7000 no es lo mismo que 18.7. Cambié mi software durante los 2 años, así que tengo ambos formatos.


¿Decepcionado de Postgres? ¿Access incluso tiene matrices?
ypercubeᵀᴹ

No lo sé, pero puede eliminar duplicados, es un problema bastante común en la limpieza de datos. Seleccionar distinto está lo suficientemente cerca. No siempre tiene control sobre sus datos sin procesar del mundo real.
Alan Corey
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.