Tengo una mesa con 50K filas. En realidad es una tabla PostGIS.
La consulta tiene 4 partes (1 obligatoria) (3 opcionales)
- cuadro de intersección (un rectángulo de geografía) con 4 lat, largo (uso st_intersects) [Obligatorio]
- Rango de fechas (min, max) en un campo de fecha
- 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.
- 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.
- 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.
- Todo lo que estaba buscando eran algunos consejos, sugerencias y pautas.
- Leí esta pequeña publicación excelente: https://devcenter.heroku.com/articles/postgresql-indexes#managing-and-maintaining-indexes acerca de los índices
- 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)
- 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).
- 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.
- 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.
- Si creo algunos índices compuestos o de valor único adicionales, el planificador es lo suficientemente inteligente como para elegir el más inteligente .....
- 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.
- 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'))
fuente
EXPLAIN ANALYZE
para la consulta.Respuestas:
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:
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 ();
fuente
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.
fuente