Ich führe PostgresSQL 9.2 aus und habe eine 12-Spalten-Beziehung mit ungefähr 6.700.000 Zeilen. Es enthält Knoten in einem 3D-Raum, von denen jeder auf einen Benutzer verweist (der ihn erstellt hat). Um abzufragen, welcher Benutzer wie viele Knoten erstellt hat, gehe ich wie folgt vor ( explain analyze
für weitere Informationen hinzugefügt ):
EXPLAIN ANALYZE SELECT user_id, count(user_id) FROM treenode WHERE project_id=1 GROUP BY user_id;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------
HashAggregate (cost=253668.70..253669.07 rows=37 width=8) (actual time=1747.620..1747.623 rows=38 loops=1)
-> Seq Scan on treenode (cost=0.00..220278.79 rows=6677983 width=8) (actual time=0.019..886.803 rows=6677983 loops=1)
Filter: (project_id = 1)
Total runtime: 1747.653 ms
Wie Sie sehen, dauert dies ungefähr 1,7 Sekunden. In Anbetracht der Datenmenge ist das nicht schlecht, aber ich frage mich, ob dies verbessert werden kann. Ich habe versucht, einen BTree-Index für die Benutzerspalte hinzuzufügen, aber das hat in keiner Weise geholfen.
Haben Sie alternative Vorschläge?
Der Vollständigkeit halber ist dies die vollständige Tabellendefinition mit allen Indizes (ohne Fremdschlüsseleinschränkungen, Referenzen und Trigger):
Column | Type | Modifiers
---------------+--------------------------+------------------------------------------------------
id | bigint | not null default nextval('concept_id_seq'::regclass)
user_id | bigint | not null
creation_time | timestamp with time zone | not null default now()
edition_time | timestamp with time zone | not null default now()
project_id | bigint | not null
location | double3d | not null
reviewer_id | integer | not null default (-1)
review_time | timestamp with time zone |
editor_id | integer |
parent_id | bigint |
radius | double precision | not null default 0
confidence | integer | not null default 5
skeleton_id | bigint |
Indexes:
"treenode_pkey" PRIMARY KEY, btree (id)
"treenode_id_key" UNIQUE CONSTRAINT, btree (id)
"skeleton_id_treenode_index" btree (skeleton_id)
"treenode_editor_index" btree (editor_id)
"treenode_location_x_index" btree (((location).x))
"treenode_location_y_index" btree (((location).y))
"treenode_location_z_index" btree (((location).z))
"treenode_parent_id" btree (parent_id)
"treenode_user_index" btree (user_id)
Bearbeiten: Dies ist das Ergebnis, wenn ich die von @ypercube vorgeschlagene Abfrage (und den Index) verwende (Abfrage dauert ungefähr 5,3 Sekunden ohne EXPLAIN ANALYZE
):
EXPLAIN ANALYZE SELECT u.id, ( SELECT COUNT(*) FROM treenode AS t WHERE t.project_id=1 AND t.user_id = u.id ) AS number_of_nodes FROM auth_user As u;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------------
Seq Scan on auth_user u (cost=0.00..6987937.85 rows=46 width=4) (actual time=29.934..5556.147 rows=46 loops=1)
SubPlan 1
-> Aggregate (cost=151911.65..151911.66 rows=1 width=0) (actual time=120.780..120.780 rows=1 loops=46)
-> Bitmap Heap Scan on treenode t (cost=4634.41..151460.44 rows=180486 width=0) (actual time=13.785..114.021 rows=145174 loops=46)
Recheck Cond: ((project_id = 1) AND (user_id = u.id))
Rows Removed by Index Recheck: 461076
-> Bitmap Index Scan on treenode_user_index (cost=0.00..4589.29 rows=180486 width=0) (actual time=13.082..13.082 rows=145174 loops=46)
Index Cond: ((project_id = 1) AND (user_id = u.id))
Total runtime: 5556.190 ms
(9 rows)
Time: 5556.804 ms
Edit 2: Dies ist das Ergebnis, wenn ich ein index
On project_id, user_id
(aber noch keine Schemaoptimierung) verwende, wie von @ erwin-brandstetter vorgeschlagen (die Abfrage läuft mit 1,5 Sekunden mit der gleichen Geschwindigkeit wie meine ursprüngliche Abfrage):
EXPLAIN ANALYZE SELECT user_id, count(user_id) as ct FROM treenode WHERE project_id=1 GROUP BY user_id;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------
HashAggregate (cost=253670.88..253671.24 rows=37 width=8) (actual time=1807.334..1807.339 rows=38 loops=1)
-> Seq Scan on treenode (cost=0.00..220280.62 rows=6678050 width=8) (actual time=0.183..893.491 rows=6678050 loops=1)
Filter: (project_id = 1)
Total runtime: 1807.368 ms
(4 rows)
project_id
und user_id
? Wird die Tabelle ständig aktualisiert oder können Sie (für einige Zeit) mit einer materialisierten Ansicht arbeiten?
Users
mituser_id
als Primärschlüssel?