Tengo la siguiente tabla/índices -Postgres que combinan varios índices
CREATE TABLE test
(
coords geography(Point,4326),
user_id varchar(50),
created_at timestamp
);
CREATE INDEX ix_coords ON test USING GIST (coords);
CREATE INDEX ix_user_id ON test (user_id);
CREATE INDEX ix_created_at ON test (created_at DESC);
Ésta es la consulta que desea ejecutar:
select *
from updates
where ST_DWithin(coords, ST_MakePoint(-126.4, 45.32)::geography, 30000)
and user_id='3212312'
order by created_at desc
limit 60
Cuando ejecuto la consulta sólo se utiliza ix_coords
índice. ¿Cómo puedo asegurarme de que Postgres usa los índices ix_user_id
y ix_created_at
para la consulta?
Esta es una nueva tabla en la que hice una inserción masiva de datos de producción. total de filas en la tabla test
: 15.069.489
Me postulo PostgreSQL 9.2.1 (con Postgis) con (effective_cache_size = 2 GB). Este es mi OSX local con 16 GB de RAM, Core i7/2.5 GHz, disco que no es SSD.
Adición de la salida de EXPLAIN ANALYZE
-
Limit (cost=71.64..71.65 rows=1 width=280) (actual time=1278.652..1278.665 rows=60 loops=1)
-> Sort (cost=71.64..71.65 rows=1 width=280) (actual time=1278.651..1278.662 rows=60 loops=1)
Sort Key: created_at
Sort Method: top-N heapsort Memory: 33kB
-> Index Scan using ix_coords on test (cost=0.00..71.63 rows=1 width=280) (actual time=0.198..1278.227 rows=178 loops=1)
Index Cond: (coords && '0101000020E61000006666666666E63C40C3F5285C8F824440'::geography)
Filter: (((user_id)::text = '4f1092000b921a000100015c'::text) AND ('0101000020E61000006666666666E63C40C3F5285C8F824440'::geography && _st_expand(coords, 30000::double precision)) AND _st_dwithin(coords, '0101000020E61000006666666666E63C40C3F5285C8F824440'::geography, 30000::double precision, true))
Rows Removed by Filter: 3122459
Total runtime: 1278.701 ms
ACTUALIZACIÓN:
Sobre la base de las sugerencias a continuación he intentado índice en los cables + user_id:
CREATE INDEX ix_coords_and_user_id ON updates USING GIST (coords, user_id);
..pero sale el siguiente error:
ERROR: data type character varying has no default operator class for access method "gist"
HINT: You must specify an operator class for the index or define a default operator class for the data type.
ACTUALIZACIÓN:
Así que el CREATE EXTENSION btree_gist;
resolvió el problema del índice compuesto btree/gist. Y ahora mi índice parece
CREATE INDEX ix_coords_user_id_created_at ON test USING GIST (coords, user_id, created_at);
NOTA: btree_gist no acepta DESC/ASC.
nuevo plan de consulta:
Limit (cost=134.99..135.00 rows=1 width=280) (actual time=273.282..273.292 rows=60 loops=1)
-> Sort (cost=134.99..135.00 rows=1 width=280) (actual time=273.281..273.285 rows=60 loops=1)
Sort Key: created_at
Sort Method: quicksort Memory: 41kB
-> Index Scan using ix_updates_coords_user_id_created_at on updates (cost=0.00..134.98 rows=1 width=280) (actual time=0.406..273.110 rows=115 loops=1)
Index Cond: ((coords && '0101000020E61000006666666666E63C40C3F5285C8F824440'::geography) AND ((user_id)::text = '4e952bb5b9a77200010019ad'::text))
Filter: (('0101000020E61000006666666666E63C40C3F5285C8F824440'::geography && _st_expand(coords, 30000::double precision)) AND _st_dwithin(coords, '0101000020E61000006666666666E63C40C3F5285C8F824440'::geography, 30000::double precision, true))
Rows Removed by Filter: 1
Total runtime: 273.331 ms
La consulta se está desempeñando mejor que antes, casi un segundo mejor, pero todavía no es muy bueno. ¿Supongo que esto es lo mejor que puedo conseguir? Esperaba algo entre 60 y 80 ms. También tomando order by created_at desc
de la consulta, reduce otros 100 ms, lo que significa que no puede usar el índice. ¿Cualquier forma de arreglar esto?
Postgres utiliza un planificador basado en los costos. Incluso si PUEDE usar el índice, puede que no sea tan rápido como no usarlo. Puedes jugar con random_page_cost y cpu * cost vars para ver si puedes hablar usando esos índices. Use explicar analizar para ver qué decide hacer y qué tan rápido es. –
El uso de un índice también depende de las estadísticas disponibles. ¿Cuántas filas realmente tienen 'user_id = '3212312''? ¿Has hecho un 'análisis de vacío' antes de esta consulta (al menos después de completar la tabla)? – wildplasser
Para ver qué hace cuando el índice 'ix_coords' no está disponible, si puede usar el otro índice y cuál es el costo, intente' BEGIN; INDICE DE GOTA ix_coords ON thetable; EXPLICAR ANALIZAR the_query; ROLLBACK; '. –