2012-05-04 11 views
7

Tengo una consulta en la que quiero seleccionar a todos los usuarios que les gusta un determinado grupo de artistas. También hay algunos otros criterios WHERE en el país, etc. Aquí se muestra el esquema.Postgresql Query - Ordenando por resultado de la subconsulta

  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 | 
+----------+------------+ +-----------+------------+ +--------+--------+ 

Quiero pedir por el número de artistas que les gusta. También quiero incluir usuarios a los que no les guste ninguno de los artistas pero que coincidan con los criterios WHERE. El conjunto de resultados esperado se vería así.

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

que he estado tratando de hacerlo usando una sub consulta para obtener el match_count y pedidos por eso, sino que está actuando muy lentamente así que pensé que no tendría que haber una mejor manera.

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; 

Estoy usando Postgresql 9.0.7. ¿Alguna idea?

Respuesta

6

Su consulta está ejecutando una sub consulta por cada fila en users. Tales consultas se llaman "subconsultas correlacionadas" y su rendimiento, muy comprensiblemente, apesta.

el contrario desea una combinación:

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; 

Esta consulta obtener las filas que unen mucho más eficiente, suponiendo que tiene un índice en favourite_artists(user_id) - o mejor aún, una multi-column indexfavourite_artists(user_id, artist_id).

+1

+1 por la muy buena introducción. :) –

+1

Depender de la posición en la cláusula ORDER BY infringe la teoría relacional, que sostiene que el orden de los campos en el conjunto de resultados no está determinado. Sugiero "ORDER BY match_count" en su lugar. –

+1

@JoelFinkel No "viola" nada. El orden de las columnas se define * dentro de la consulta *, por lo que la encapsulación está intacta. Está bien. No puedo entender por qué algunas personas tienen sus bragas en un grupo sobre este tema increíblemente trivial que no hace absolutamente ninguna diferencia en absoluto al resultado o cualquier otra cosa para el caso. Hay peces más grandes para freír. En realidad, hay * peces * para freír, esto ni siquiera es un pescado. No es nada. – Bohemian

Cuestiones relacionadas