2012-05-04 28 views
7

Belirli bir sanatçı grubunu seven tüm kullanıcıları seçmek istediğim bir sorgum var. Ayrıca, ülke hakkında başka WHERE kriterleri de vardır. Şemanın neye benzediğini burada görebilirsiniz.Postgresql Sorgu - Alt sorgu sonucuyla sıralama

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

Onları istedikleri sanatçıların sayısına göre sıralamak istiyorum. Ayrıca, sanatçılardan hoşlanmayan ancak WHERE kriterlerine uyan kullanıcıları da eklemek istiyorum. Beklenen sonuç kümesi benzeyecek.

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

ben bundan match_count ve sipariş almak için bir alt sorgu kullanarak bunu yapmak için çalışıyorum ama oldukça yavaş yüzden daha iyi bir yolu olmak zorunda düşündüm gösteri yapıyor.

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; 

Postgresql 9.0.7 kullanıyorum. Düşüncesi olan var mı?

cevap

6

Sorgulama, users numaralı telefondan her satır için bir alt sorgu yürütmektedir. Bu tür sorgular "korelasyonlu alt sorgular" olarak adlandırılır ve performansı oldukça anlaşılır bir şekilde berbattır. daha iyisi multi-column indexfavourite_artists(user_id, artist_id) veya - Bir favourite_artists(user_id) üzerinde endeksine sahip varsayarak

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; 

Bu sorgu çok daha verimli bir şekilde katılmadan satırları alacak:

Bunun yerine bir katılmak istiyorum. Çok güzel bir tanıtım için

+1

+1. :) –

+1

ORDER BY deyimindeki konuma dayanarak, sonuç kümesindeki alanların sırasının belirlenmediğini belirten ilişkisel kuralı ihlal ediyor. Bunun yerine "match_count" siparişini öneririm. –

+1

@JoelFinkel Herhangi bir şeyi "ihlal etmiyor". Sütunların sırası * sorgu içinde * tanımlanmıştır, bu yüzden kapsülleme sağlamdır. Bu iyi. Bazı insanların niçin bu kadar önemli bir mesele olduğuna ve bu sonuca ya da bu konuyla ilgili herhangi bir şeye kesinlikle bir fark getirmeyen bir kağıda neden külot aldığını anlayamıyorum. Kızartmak için daha büyük balıklar var. Aslında, * balık * kızartmak için vardır - bu bir balık bile değil. Önemli değil. – Bohemian