Orden de columnas en un índice compuesto en PostgreSQL (y orden de consulta)

9

Tengo una mesa con 50K filas. En realidad es una tabla PostGIS.

La consulta tiene 4 partes (1 obligatoria) (3 opcionales)

  1. cuadro de intersección (un rectángulo de geografía) con 4 lat, largo (uso st_intersects) [Obligatorio]
  2. Rango de fechas (min, max) en un campo de fecha
  3. Tipo de archivo (un conjunto de hasta 8 valores de texto) que actualmente usa IN (.....) pero puedo convertirlo en una tabla temporal si es necesario. Veo que a mucha gente no le gusta IN.
  4. País (un valor de texto).

Espero alrededor de 100 - 4,000 filas devueltas

Si creo un índice compuesto en la tabla, ¿qué columna debo usar primero? El grano fino es probablemente la ubicación (los datos se extienden por todo el mundo). Actualmente lo tengo como índice GIST.

Los otros índices serían BTREE.

Mi intuición dice que use el grano fino y, por supuesto, el último. Por ejemplo, solo hay unos 12 tipos de archivos, por lo que sería un gran depósito para el índice.

¿Qué dicen los gurús de PostgreSQL y PostGIS (que conocen las partes internas del sistema)?


ACTUALIZAR:

Déjame agudizar esta pregunta.

  1. No quiero que nadie tenga que hacer el trabajo que debo hacer. Respeto demasiado tu tiempo. Así que llegaré al análisis de explicación más adelante.
  2. Todo lo que estaba buscando eran algunos consejos, sugerencias y pautas.
  3. Leí esta pequeña publicación excelente: https://devcenter.heroku.com/articles/postgresql-indexes#managing-and-maintaining-indexes acerca de los índices
  4. Lo que normalmente hago es crear 4 índices separados (geo-box, nombre del país, tipo de archivo y fecha), pero qué quieren ver qué haría una consulta compuesta.

Dime si alguno de estos supuestos está mal. (Soy bastante nuevo en la idea de los índices compuestos)

  1. El orden es importante. Elija como primer índice el que reducirá más las filas (en mi caso, la ubicación (geografía), que es un polígono simple o un polígono múltiple, sería lo mejor).
  2. A veces las consultas omitirán los índices. Pero si creo una consulta compuesta con clave (# 1, # 2, # 3, # 4), incluso si el usuario crea algo que pide # 1, # 3, el planificador seguirá utilizando la consulta compuesta única, ya que ordenan es mantenido.
  3. Normalmente crearía tres consultas BTREE y una GIST (para el tipo de geografía). PostGIS no admite la creación de un compuesto a partir de múltiples tipos de índice. Entonces tendré que usar GIST el índice compuesto. Pero eso no debería lastimar las cosas.
  4. Si creo algunos índices compuestos o de valor único adicionales, el planificador es lo suficientemente inteligente como para elegir el más inteligente .....
  5. El nombre del país puede tener unos 250 valores diferentes, y obviamente está fuertemente vinculado a la ubicación (geobox), pero si el siguiente mejor índice para reducir el tamaño de la fila es file_type, debería usarlo a continuación. No espero que los usuarios usen a menudo el país o la fecha en sus conjuntos de consultas.
  6. NO tengo que preocuparme por crear un índice compuesto de 4 claves que aumentará en gran medida el tamaño de los datos del índice. Es decir, si un índice de una clave fuera el 90% del aumento del rendimiento, no está de más agregar 3 elementos más para hacerlo compuesto. Por el contrario, realmente debería crear ambos índices. Un índice de geografía único, y también un índice compuesto, y deje que el planificador descubra cuál es el mejor, y tendrá en cuenta el tamaño de la tabla de índice.

Una vez más, no le pido a nadie que diseñe mi solución, no me burlo del trabajo de los demás. Pero necesito cosas que la documentación de PostGreSQL no me dice acerca de la implementación

[La razón por la que todavía no tengo un resultado EXPLICAR para mostrar es que tengo que crear esta tabla de filas de 25K a partir de una tabla de filas de 24M. Está tomando más tiempo de lo que pensaba. Estoy agrupando cosas en 1,000 grupos de elementos y dejo que el usuario consulte en la tabla de filas de 25K. Pero mi próxima pregunta involucrará el uso de los resultados de esa consulta para ir a la tabla de filas MASTER 25M y extraer las cosas, y ahí es donde el rendimiento del índice compuesto HIT realmente].


consulta de ejemplo a continuación:


SELECT
    public.product_list_meta_mv.cntry_name       AS country,
    public.product_list_meta_mv.product_producer AS producer,
    public.product_list_meta_mv.product_name     AS prod_name,
    public.product_list_meta_mv.product_type     AS ptype,
    public.product_list_meta_mv.product_size     AS size,
    ST_AsGeoJSON(public.product_list_meta_mv.the_geom, 10, 2)          AS outline
FROM
    public.product_list_meta_mv 
WHERE
    public.product_list_meta_mv.cntry_name = 'Poland' 
AND
    ST_Intersects(public.product_list_meta_mv.the_geom,
    st_geogfromtext('SRID=4326;POLYGON((21.23107910156250 51.41601562500000,
                                        18.64379882812500 51.41601562500000,
                                        18.64379882812500 48.69415283203130,
                                        21.23107910156250 48.69415283203130,
                                        21.23107910156250 51.41601562500000))')) 
AND (date >= '1/2/1900 5:00:00 AM' 
 AND date <= '2/26/2014 10:26:44 PM')
AND (public.product_list_meta_mv.product_type in
    ('CIB10','DTED0','DTED1','DTED2','CIB01','CIB05')) ;

EXPLICAR ANÁLISIS resultados (no puse ningún índice compuesto, y por la velocidad que estoy viendo no sé si es necesario).

"Bitmap Heap Scan on catalog_full cat  (cost=4.33..37.49 rows=1 width=7428) (actual time=1.147..38.051 rows=35 loops=1)"
"  Recheck Cond: ('0103000020E61000000100000005000000000000005838354000000000AEB0494000000000A0A7324000000000AEB0494000000000A0A73240000000006C5D48400000000058383540000000006C5D4840000000005838354000000000AEB04940'::geography && outline)"
"  Filter: (((type)::text = ANY ('{CADRG,CIB10,DTED1,DTED2}'::text[])) AND (_st_distance('0103000020E61000000100000005000000000000005838354000000000AEB0494000000000A0A7324000000000AEB0494000000000A0A73240000000006C5D48400000000058383540000000006C5D4840000000005838354000000000AEB04940'::geography, outline, 0::double precision, false) < 1e-005::double precision))"
"  Rows Removed by Filter: 61"
"  ->  Bitmap Index Scan on catalog_full_outline_idx  (cost=0.00..4.33 rows=8 width=0) (actual time=0.401..0.401 rows=96 loops=1)"
"        Index Cond: ('0103000020E61000000100000005000000000000005838354000000000AEB0494000000000A0A7324000000000AEB0494000000000A0A73240000000006C5D48400000000058383540000000006C5D4840000000005838354000000000AEB04940'::geography && outline)"
"Total runtime: 38.109 ms"

EXPLAIN ANALYZE SELECT pid,product_name,type,country,date,size,cocom,description,egpl_date,ST_AsGeoJSON(outline, 10, 2) AS outline 
FROM portal.catalog_full AS cat 
WHERE ST_Intersects(st_geogfromtext('SRID=4326;POLYGON((21.2200927734375 51.38031005859375, 18.65478515625 51.38031005859375, 18.65478515625 48.7298583984375, 21.2200927734375 48.7298583984375, 21.2200927734375 51.38031005859375))'), cat.outline) 
AND (cat.type in ('CADRG','CIB10','DTED1','DTED2'))
Dr.YSG
fuente
2
Proporcione la consulta real, por favor.
ypercubeᵀᴹ
¿El "3 opcional" significa que la consulta puede tener 8 variaciones diferentes (dependiendo de si las opciones 2,3,4 están activadas o no)?
ypercubeᵀᴹ
Hay 4 componentes AND en el DÓNDE. En st_intersects es obligatorio, los otros pueden estar allí o no. Pero quiero tratar el caso en el que todos están presentes.
2
Voté para migrar la pregunta a dba.se, esta es una consulta compleja con condiciones de rango múltiple.
ypercubeᵀᴹ
1
Mostrar EXPLAIN ANALYZEpara la consulta.
Craig Ringer

Respuestas:

4

Como parte de mi trabajo, mantengo una base de datos PostgreSQL bastante grande (alrededor de 120 gb en disco, varias tablas de varias millones de filas) y he recopilado algunos trucos sobre cómo acelerar las consultas. Primero algunos comentarios sobre sus suposiciones:

  1. Sí, el orden es importante, pero solo el primero es realmente diferente, el resto son índices de segunda clase.
  2. No estoy seguro de que siempre usará ambos, supongo que el planificador de consultas usará el n. ° 1 y luego hará algo inteligente con el resto.
  3. No tengo experiencia con GIST.
  4. Sí, agregue todos los índices primero, vea qué se usa más y qué ofrece el mejor rendimiento.
  5. Supongo que intente ambos y mida lo que funciona mejor. Intente reescribir el sql con diferentes subconsultas, tal vez país y hora en una, luego únase con la consulta de intersección. No he notado ningún problema de rendimiento con las cláusulas IN, siempre que la lista IN no tenga miles de elementos. Supongo que unas pocas consultas diferentes ajustadas específicamente según los criterios de entrada disponibles darán los mejores resultados.
  6. Sugeriría no hacer un índice de 4 vías. Intente crear uno y luego verifique el tamaño, pueden ser realmente enormes. En mi experiencia, cuatro índices de 1 clave han sido casi tan rápidos como un solo índice de 4 vías. Un truco que funciona bien para algunas consultas específicas son los índices parciales, es decir, algo como esto:

    CREATE INDEX ON table_x (key1, key2, key3) WHERE some_x_column = 'XXXX';

He creado alias en mi archivo .psqlrc con consultas para ayudar a encontrar qué índices agregar o eliminar. Siéntase libre de verlos en GitHub: .psql

Utilizo mucho: seq_scans y: bigtables, y luego \ d table_name para obtener detalles sobre la tabla. No olvide restablecer las estadísticas después de haber realizado algunos cambios, seleccione pg_stat_reset ();

Claes Mogren
fuente
1
Estos son excelentes consejos. Seguí su consejo, y luego usé esto para hacer un experimento en una tabla mucho más grande que mantenemos (43 millones de filas). Los resultados están en: dba.stackexchange.com/questions/61084/…
Dr.YSG
1

Creo que lo más probable para ayudar (si es que hay algo) sería agregar product_type como una segunda columna al índice general. Pero sin saber cuántas filas coinciden con cada una de las condiciones AND (de forma aislada) para sus consultas típicas / problemáticas, solo podemos adivinar.

Cuando me acerco a esto, lo primero que hago es ejecutar la consulta en forma simplificada, donde la cláusula WHERE solo tiene una condición, cada una tomada a su vez, en EXPLAIN ANALYZE. Mire las filas estimadas y las filas reales para cada una.

jjanes
fuente
vea mi actualización anterior, pero creo que me está dando una buena ventaja, piense en ordenar los índices por los cuales se reduce la salida de la fila más rápido. ¿Está bien?
Dr.YSG