Consultas que devuelven conjuntos de datos muy grandes en PostGIS

8

Tengo una consulta PostGIS que devolverá varios millones de filas:

SELECT 
 t1.id AS id1,
 t2.id AS id2,
 ABS(t1.mean_h - t2.mean_h) AS h_diff, 
 ST_Distance(t1.the_geom, t2.the_geom) AS dist  
FROM tas_ponds as t1, tas_ponds as t2 
WHERE
 (t1.gid > t2.gid) AND
 ST_DWithin(t1.the_geom, t2.the_geom, 17000)

Cuando corro psql, me sale un out of memory for query resulterror.

Google sugiere que este es un error dentro de psql en lugar de postgres / PostGIS. ¿Enmendar la consulta en el formulario SELECT ... INTO x FROM ...solucionaría el problema? ¿Existen otros enfoques recomendados para tratar con conjuntos de datos muy grandes?

fmark
fuente

Respuestas:

7

Un poco de investigación confirma que este es un problema del cliente de Postgres, independientemente de las consideraciones espaciales o del servidor: el cliente tiene una cantidad limitada de memoria para almacenar los resultados antes de mostrarlos en la pantalla, lo cual está excediendo.

El enfoque recomendado para manejar esto es usar un enfoque DECLARE / FETCH para acceder a los datos en bloques más pequeños que el conjunto de resultados total. También podría crear una vista con componentes de la consulta (por ejemplo, distancia) para reducir la memoria necesaria para la operación de consulta en sí.

scw
fuente
5

scw me atrapó por dos minutos, así que no repetiré su respuesta. Aquí hay algunas otras posibles soluciones:

  • Edite la Memorysección de postgresql.conf. Intente ver si tiene configuraciones de memoria extremadamente bajas que podrían impedir que se ejecute la consulta.

  • Intente escribir la consulta en un archivo y ejecutarla desde la línea de comandos, utilizando:

    psql -f nombrearchivo nombre_bd> archivo_salida

  • Si tiene la intención de utilizar los resultados en una aplicación externa, intente ejecutar la consulta con un cursor desde afuera psql. Por ejemplo, un script de Python que ejecutaría su consulta:

guión:

try:
    conn = psycopg2.connect("dbname='' user='' host='' password=''") # Fill in
    cur = conn.cursor()
except:
        print 'Unable to connect to the database'
else:
        print 'Connected to database.'

query="""YOUR
         QUERY
         HERE"""
cur.execute(query)

Un cursor es iterable, por lo que puede:

for result in cur:
    print result

O consíguelos todos:

 results=cur.fetchall()
Adam Matan
fuente
2
Podría estar equivocado, pero no creo que las primeras (y tal vez la segunda) soluciones funcionen. El primero modifica la memoria del servidor, y este es un problema del cliente, no relacionado con la memoria disponible dentro del DMBS, y el segundo probablemente sufrirá el mismo problema a menos que el problema sea simplemente almacenarlo en la pantalla. Su tercera solución es mejor que la mía IMO, ya que proporciona un control detallado en un entorno flexible con el cursor, que es un poco más complicado en SQL sin formato. +1
scw
@scw probablemente tenga razón sobre la primera (y quizás la segunda) solución. El problema es que, a veces, estos trucos específicos parecen funcionar con PostgreSQL, pueden mejorar el rendimiento general y requieren poco tiempo y esfuerzo para intentarlo. Aprendí mucho de tu respuesta.
Adam Matan el
2

Para el registro, en mi caso, el almacenamiento del conjunto de datos devuelto en otra tabla utilizando la SELECT ... INTO ...sintaxis funcionó.

No solo resolvió el problema de falta de memoria, sino que también fue sustancialmente más rápido que la consulta original.

fmark
fuente
1

La indexación es muy importante en Postgres y PostGIS

http://postgis.refractions.net/docs/ch04.html#id2794434

Recomendar índices GiST (árboles de búsqueda generalizados) para conjuntos de datos muy grandes ... (también es "nulo seguro") ejemplo CREATE INDEX [indexname] ON [tablename] USANDO GIST ([geometryfield]);

Después de crear un índice, es importante forzar a PostgreSQL a recopilar estadísticas de tabla, que se utilizan para optimizar los planes de consulta

ANÁLISIS DE VACÍO [nombre_tabla] [nombre_columna]; SELECT UPDATE_GEOMETRY_STATS ([nombre_tabla], [nombre_columna]);

También una buena referencia es: Aprovechar los índices http://postgis.refractions.net/docs/ch04.html#id2794685

Mapperz
fuente
Sí, indexé y aspiré las tablas, y confirme que mis índices se están utilizando a través de EXPLAIN, etc. Sin embargo, mi problema no es con la velocidad (en este punto), es con un error de falta de memoria.
fmark