Ich habe folgende Tabelle/Indizes kombinieren -Postgres mehrere Indizes
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);
Dies ist die Abfrage, die ich ausführen wollen:
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
Wenn ich die Abfrage ausführen verwendet es nur ix_coords
Index. Wie kann ich sicherstellen, dass Postgres und ix_created_at
Index für die Abfrage verwendet?
Dies ist eine neue Tabelle, in der ich Massenproduktionsdaten eingefügt habe. Insgesamt Zeilen in der Tabelle test
: 15.069.489
Ich bin mit PostgreSQL 9.2.1 (mit Postgis) mit (effective_cache_size = 2GB). Dies ist mein lokaler OSX mit 16 GB RAM, Core i7/2.5 GHz, Nicht-SSD-Festplatte.
Hinzufügen der EXPLAIN ANALYZE
Ausgabe -
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
UPDATE:
Auf der Grundlage der Vorschläge unten I Index versucht, auf Schnüre + user_id:
CREATE INDEX ix_coords_and_user_id ON updates USING GIST (coords, user_id);
..aber die folgende Fehlermeldung zu erhalten:
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.
UPDATE:
So löste die CREATE EXTENSION btree_gist;
den btree/gist Verbund Index Problem. Und jetzt sieht mein Index wie
CREATE INDEX ix_coords_user_id_created_at ON test USING GIST (coords, user_id, created_at);
HINWEIS: btree_gist akzeptiert nicht DESC/ASC.
Neuer Abfrage-Plan:
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
Die Abfrage durchführen wird, besser als zuvor, fast eine Sekunde besser, aber immer noch nicht groß. Ich denke, das ist das Beste, was ich bekommen kann ?? Ich hoffte irgendwo um 60-80ms. Wenn Sie aus der Abfrage entfernen, werden weitere 100ms entfernt, was bedeutet, dass der Index nicht verwendet werden kann. Wie auch immer, um das zu beheben?
Postgres verwendet einen kostenbasierten Planer. Auch wenn es den Index verwenden kann, ist es möglicherweise nicht so schnell wie es nicht verwendet wird. Sie können mit random_page_cost und cpu * cost vars spielen, um zu sehen, ob Sie mit diesen Indizes sprechen können. Verwenden Sie explain analyze, um zu sehen, was es zu tun hat und wie schnell es ist. –
Die Verwendung eines Index hängt auch von den verfügbaren Statistiken ab. Wie viele Zeilen haben eigentlich 'user_id =' 3212312''? Haben Sie vor dieser Abfrage eine "Vakuumanalyse" durchgeführt (zumindest nach dem Auffüllen der Tabelle)? – wildplasser
Um zu sehen, was es macht, wenn der 'ix_coords' Index nicht verfügbar ist - ob es den anderen Index benutzen kann und wie hoch die Kosten sind - probiere' BEGIN; DROP INDEX ix_coords ON die Tabelle; EXPLAIN ANALYSE the_query; ROLLBACK; '. –