2011-11-26 10 views
7

Ho avuto una query che è stata eseguita bene per circa 2 anni. La tabella del database ha circa 50 milioni di righe e sta crescendo lentamente. Questa settimana scorsa, una delle mie domande è stata quella di tornare quasi istantaneamente a prendere ore per correre.Query semplice che funziona da anni, poi improvvisamente molto lento

Rank.objects.filter(site=Site.objects.get(profile__client=client, profile__is_active=False)).latest('id') 

Ho ristretto la query lenta al modello di rango. Sembra avere qualcosa a che fare con l'uso del metodo latest(). Se chiedo solo un queryset, restituisce immediatamente un queryset vuoto.

#count returns 0 and is fast 
Rank.objects.filter(site=Site.objects.get(profile__client=client, profile__is_active=False)).count() == 0 
Rank.objects.filter(site=Site.objects.get(profile__client=client, profile__is_active=False)) == [] #also very fast 

Ecco i risultati dell'esecuzione di EXPLAIN. http://explain.depesz.com/s/wPh

e spiegare analizza: http://explain.depesz.com/s/ggi

ho provato l'aspirapolvere sul tavolo, nessun cambiamento. Esiste già un indice nel campo "sito" (ForeignKey).

Stranamente, se eseguo questa stessa query per un altro client che ha già oggetti di rango associati al suo account, la query restituisce molto rapidamente ancora una volta. Quindi sembra che questo sia solo un problema quando non sono oggetti Rank per quel client.

Qualche idea?

Versioni: Postgres 9.1, Django tronco 1.4 svn rev 17047

risposta

0

Bene, non hai mostrato l'attuale SQL, quindi è difficile esserne certi. Tuttavia, l'output di spiegazioni suggerisce che il modo più rapido per trovare una corrispondenza è la scansione di un indice su "id" all'indietro finché non trova il client in questione.

Dato che hai detto che è stato veloce fino a poco tempo fa, probabilmente non è una scelta sciocca. Tuttavia, c'è sempre la possibilità che il record di un particolare cliente sia proprio all'estremità di questa ricerca.

Così - provare due cose in primo luogo:

  1. Eseguire una analizzare sul tavolo in questione, vedere se che dà il pianificatore abbastanza informazioni.
  2. In caso contrario, aumentare le statistiche (ALTER TABLE ... SET STATISTICS) sulle colonne in questione e riesaminare. Vedi se lo fa.

http://www.postgresql.org/docs/9.1/static/planner-stats.html

se questo non è ancora aiutare, quindi prendere in considerazione un indice su (client, id), e rilasciare l'indice id (se non necessario altrove). Questo dovrebbe darti risposte fulminee.

+0

L'impostazione di un indice composto sul campo nel WHERE e il campo in ORDER BY hanno fatto il trucco. Si scopre che il pianificatore di query stava eseguendo la scansione dell'intero indice per l'ordinamento e quindi facendo il filtro. L'indice composto ha fatto il trucco. – erikcw

0

latests viene normalmente utilizzato per il confronto la data, forse si dovrebbe cercare di Ordina per ID decrescente e quindi limitare a uno.

+0

L'ho provato e c'era anche un ritardo altrettanto lungo. Quando guardo l'SQL grezzo generato dall'ORM, entrambi producono un output equivalente. – erikcw