2016-06-12 13 views
0

Ich habe eine Messages Tabelle mit user_id Feld (Zeichenfolge). Eine Abfrage für insgesamt eindeutige Benutzer ist extrem langsam mit mehr als einer Million Datensätze.Langsame activerecord/postgres Abfrage nicht mit Index

Message.where(created_at: start_date..end_date).select(:user_id).distinct(:user_id).count 
=> (120145.6ms) SELECT DISTINCT COUNT(DISTINCT "messages"."user_id") FROM "messages" WHERE ("messages"."created_at" BETWEEN '2016-05-14 04:00:00.000000' AND '2016-06-13 03:59:59.999000') 

Ich habe Indizes auf user_id & created_at, aber Postgres scheint nicht, sie zu benutzen:

Schema

add_index "messages", ["user_id"], name: "index_messages_on_user_id", using: :btree 
add_index "messages", ["created_at"], name: "index_messages_on_created_at", using: :btree 

PG Erklären

                 QUERY PLAN 
----------------------------------------------------------------------------------------------------------------------------------------------------------------- 
HashAggregate (cost=56111.04..56291.89 rows=18085 width=29) 
    Group Key: user_id 
    -> Seq Scan on messages (cost=0.00..52215.65 rows=1558153 width=29) 
     Filter: ((created_at >= '2016-05-14 04:00:00'::timestamp without time zone) AND (created_at <= '2016-06-13 03:59:59.999'::timestamp without time zone)) 
(4 rows) 

Warum werden die Indizes nicht verwendet? Irgendwelche Tipps zur Beschleunigung der Abfrage?

Antwort

0

Der Index ist wahrscheinlich nicht selektiv genug, sodass Postgres entscheidet, dass die gesamte Tabelle gelesen werden muss. Für Ihre Anfrage würde ich einen Index auf messages(created_at, user_id) empfehlen. Postgres würde ermutigt werden, anstelle der Rohdaten den Index zu verwenden, da es sich um einen Deckungsindex handelt.

Eine andere Idee wäre, created_at (oder created_at, user_id) einen gruppierten Index zu machen. Dies hat wahrscheinlich keinen Einfluss auf die Leistung des Einschubs, da neue Datensätze höhere Werte für created_at haben und am Ende trotzdem gehen. Dies würde I/O reduzieren.

+0

Ich versuchte 'Nachrichten (created_at, user_id)' und es scheint auch diesen Index zu ignorieren :( – mnort9

+0

@ mnort9.. Versuchen Sie die 'Select distinct' zu entfernen. Es macht keinen Sinn für diese Abfrage und es könnte verwirrend sein der Optimierer –

+0

Ohne 'select' kann ich die AR-Abfrage mit' Message.distinct.count (: user_id) 'erstellen, aber es erzeugt die selbe 'SELECT DISTINCT' sql – mnort9

Verwandte Themen