2012-05-04 12 views
7

Ho una query in cui desidero selezionare tutti gli utenti a cui piace un determinato set di artisti. Ci sono anche altri criteri WHERE sul paese, ecc. Ecco come appare lo schema.Query Postgresql - Ordinamento per risultato di subquery

  users      favourite_artists    artists 

+----------+------------+ +-----------+------------+ +--------+--------+ 
| id | country | | user_id | artist_id | | id | name | 
+----------+------------+ +-----------+------------+ +--------+--------+ 
|  1 |  gb  | |  1  |  6  | | 1 | Muse | 
|  2 |  gb  | |  1  |  5  | | 2 | RATM | 
|  3 |  us  | |  1  |  3  | | 3 | ABBA | 
|  4 |  us  | |  2  |  3  | | 4 | U2 | 
+----------+------------+ +-----------+------------+ +--------+--------+ 

Voglio ordinarli per il numero di quegli artisti che gradiscono. Voglio anche includere utenti a cui non piace uno degli artisti ma che corrispondono ai criteri WHERE. Il set di risultati attesi sarebbe simile.

+--------+---------------+----------------+ 
| id | country | match_count | 
+--------+---------------+----------------+ 
| 6 |  gb  |  4  | 
| 9 |  gb  |  4  | 
| 2 |  gb  |  3  | 
| 1 |  gb  |  2  | 
| 5 |  gb  |  0  | 
| 4 |  gb  |  0  | 
+--------+---------------+----------------+ 

Ho cercato di farlo usando una subquery per ottenere il match_count e l'ordinamento per questo, ma si tratta di eseguire abbastanza lentamente così ho pensato che ci sarebbe dovuto essere un modo migliore.

SELECT users.id, users.country 
    (SELECT COUNT(*) FROM favourite_artists 
    WHERE user_id = users.id AND artist_id IN (1,3,4,9)) AS match_count   
    FROM "users" 
    WHERE users.country = 'gb' 
    ORDER BY match_count DESC; 

Sto usando Postgresql 9.0.7. qualche idea?

risposta

6

La query sta eseguendo una sottoquery per ogni riga in users. Tali query sono chiamate "subquery correlate" e le loro prestazioni, abbastanza comprensibilmente, fanno schifo.

invece si desidera un join:

SELECT users.id, users.country, count(artist_id) as match_count 
FROM users 
LEFT JOIN favourite_artists ON user_id = users.id AND artist_id IN (1,3,4,9) 
WHERE users.country = 'gb' 
GROUP BY 1, 2 
ORDER BY 3 DESC; 

Questa query ottenere le righe che uniscono molto più efficiente, a patto di avere un indice su favourite_artists(user_id) - o meglio ancora un multi-column indexfavourite_artists(user_id, artist_id).

+1

+1 per l'intro molto bello. :) –

+1

Affidarsi alla posizione nella clausola ORDER BY viola la teoria relazionale, che stabilisce che l'ordine dei campi nel set di risultati non è determinato. Suggerisco invece "ORDER BY match_count". –

+1

@JoelFinkel Non "viola" nulla. L'ordine delle colonne è definito * all'interno della query *, quindi l'incapsulamento è intatto. Va bene. Non riesco a capire perché alcune persone prendano le loro mutandine in mezzo a questo problema incredibilmente banale che non fa assolutamente alcuna differenza per il risultato o per qualsiasi altra cosa. Ci sono pesci più grandi da friggere. In realtà, ci sono * pesci * da friggere - questo non è nemmeno un pesce. Non è niente. – Bohemian

Problemi correlati