2010-01-11 18 views
7

Sitemin kullanıcılarını, katkıda bulundukları kitap yorumları ve reçete yorumları sayısına göre sıralamak için bir MySQL sorgusu çalıştırıyorum. Birden çok JOIN sorgusuyla ilk sorunlardan sonra, çok daha hızlı olan bir dizi alt soruna geçtim. Bununla birlikte, her üyeden gelen yorum sayısını ayıklayabilsem de, onları nasıl toplayacağımı anlayamıyorum, böylece toplam sayıya göre sıralayabilirim.Birkaç alt sorgunun sonuçları nasıl eklenir?

SELECT users.*, 
    (SELECT count(*) FROM bookshelf WHERE bookshelf.user_id = users.ID) as titles, 
    (SELECT count(*) FROM book_reviews WHERE book_reviews.user_id = users.ID) as bookreviews, 
    (SELECT count(*) FROM recipe_reviews WHERE recipe_reviews.user_id = users.ID) as recipereviews 
FROM users 

Ben 'reviewtotals' elde etmek için birlikte bookreviews ve recipereviews eklemeniz gerekir:

İşte şimdiki sorgu var. MySQL, takma adlar üzerinde hesaplamalar yapmak için basit sözdizimini kullanmanıza izin vermez, ancak bunu yapmanın başka bir yolu olduğunu varsayalım mı?

+0

@mandel - benim cevaba bakınız: Ben bu çok özel durumda güvenli olacak tahmin referans. Benim deneyimime göre, MySQL için genellikle sizin gibi bir çok ilişkili alt-gruptan daha hızlıdır. Durumunuzda alt sorgu çözümünün JOIN'den daha hızlı olup olmadığını öğrenmek isterim. Bana haber verebilmen için çok teşekkür ederim. –

+0

JOIN ile olan sorunlarım, felsefeden ziyade deneyimsizlikten geldi. Önceki JOIN, son derece yavaş bir sorguyla sonuçlandı: 9 saniye; Kartezyen bir ürün oluşturuyordu çıktı. Burada SO üzerinde sordum: http://stackoverflow.com/questions/2030032/is-performing-a-count-calculation-slowing-down-my-mysql-query. Alt sorgular yapmaya döndüğümde hız önemli ölçüde gelişti ve ne yaptığımı anlayabiliyordum! – mandel

+0

Hız karşılaştırması için yayınının cevabını görün - JOIN sorgunuz biraz daha hızlıdır, ancak mevcut DB boyutunda saniyenin yalnızca 4/100'ü kadardır. – mandel

cevap

9

bir alt sorgu içine sarın: güvenli ve hızlı olmasını istiyorsanız

SELECT *, 
     bookreviews + recipereviews AS totalreviews 
FROM (
     SELECT users.*, 
       (SELECT count(*) FROM bookshelf WHERE bookshelf.user_id = users.ID) as titles, 
       (SELECT count(*) FROM book_reviews WHERE book_reviews.user_id = users.ID) as bookreviews, 
       (SELECT count(*) FROM recipe_reviews WHERE recipe_reviews.user_id = users.ID) as recipereviews 
     FROM users 
     ) q 
0

Aşağıdakileri denediniz mi?

SELECT users.*, 
    (SELECT count(*) FROM bookshelf WHERE bookshelf.user_id = users.ID) as titles, 
    ((SELECT count(*) FROM book_reviews WHERE book_reviews.user_id = users.ID) + 
    (SELECT count(*) FROM recipe_reviews WHERE recipe_reviews.user_id = users.ID)) as reviewtotal 
FROM users 
+0

Teşekkürler - bu neredeyse, ama hala hesaplanan toplamın yanı sıra kitap kayıtları ve recipereviews toplamları oluşturmak gerekir. – mandel

1

İki seçenek:

Seçenek 1:

SELECT users.*, 
    (SELECT count(*) FROM bookshelf WHERE bookshelf.user_id = users.ID) as titles, 
    (SELECT count(*) FROM book_reviews WHERE book_reviews.user_id = users.ID) as bookreviews, 
    (SELECT count(*) FROM recipe_reviews WHERE recipe_reviews.user_id = users.ID) as recipereviews 
    (SELECT count(*) FROM book_reviews WHERE book_reviews.user_id = users.ID) + (SELECT count(*) FROM recipe_reviews WHERE recipe_reviews.user_id = users.ID) as reviewtotals 
FROM users 

Seçenek 2: Çirkin cehennem ve muhtemelen yavaş (sorgu önbelleği bağlıdır) 'dir geçici tabloya sonuçları kaydedin ve o zaman bu tabloyu bu çalışacaktır Belki

sorgulamak

SELECT *, bookreviews+recipereviews as reviewtotals FROM 
(SELECT users.*, 
    (SELECT count(*) FROM bookshelf WHERE bookshelf.user_id = users.ID) as titles, 
    (SELECT count(*) FROM book_reviews WHERE book_reviews.user_id = users.ID) as bookreviews, 
    (SELECT count(*) FROM recipe_reviews WHERE recipe_reviews.user_id = users.ID) as recipereviews 
FROM users) u 
0 (hiç denemedim)
+0

Neredeyse iki iş var ama ilk alt sorguya bir takma ad eklemeniz gerekiyor - daha sonra bir dakika önce olan @ Quassnoi'nin çözümüyle aynıdır. Teşekkürler! – mandel

+0

Yazarken başka bir cevap olduğunu gördüm ... –

1

, böyle yapmak:

SELECT users.* 
,  titles.num       titles 
,  book_reviews.num      book_reviews 
,  recipe_reviews.num     recipe_reviews 
,  book_reviews.num + recipe_reviews.num total_reviews 
FROM  users 
LEFT JOIN (
      SELECT user_ID, count(*) AS num 
      FROM  bookshelf 
      GROUP BY user_ID 
     ) as titles 
ON  users.ID = titles.user_ID 
LEFT JOIN (
      SELECT user_ID, count(*) AS num 
      FROM  book_reviews 
      GROUP BY user_ID 
     ) as book_reviews 
ON  users.ID = reviews.user_ID 
LEFT JOIN (
      SELECT user_ID, count(*) AS num 
      FROM  recipe_reviews 
      GROUP BY user_ID 
     ) as recipe_reviews 
ON  users.ID = recipes.user_ID 

Eğer SELECT listesinde alt sorgular sopa istiyorsanız, ve güvenli olmasını istiyoruz, Quassnoi'nin çözümüne bir göz atın.

Biraz tehlikeli bir şekilde yaşamak istiyorsanız ve yine de hızlı sonuç almak istiyorsanız, kullanıcı tanımlı değişkenleri kullanabilirsiniz. Ben JOIN` tipik bir `JOIN` ile de bu tür sorunlar çözmek` ile sorunlar hakkında merak ediyorum

SELECT users.*, 
     (SELECT count(*) FROM bookshelf WHERE bookshelf.user_id = users.ID) as titles, 
     @bookreviews:=(
      SELECT count(*) 
      FROM book_reviews 
      WHERE book_reviews.user_id = users.ID 
     ) as bookreviews, 
     @recipereviews:=(
      SELECT count(*) 
      FROM recipe_reviews 
      WHERE recipe_reviews.user_id = users.ID 
     ) as recipereviews, 
     @bookreviews + @recipereviews as total_reviews 
FROM users 
+0

İlginç: Seçenek 1, Quassnoi'nin çözümüne göre biraz daha hızlıdır (0.02 sn vs 0.024 sn), Seçenek 2 0,88 sn iken, nispeten nispeten daha yavaştır. Quassnoi'nin okunabilirlik açısından çok daha basit olduğunu (ve neler olduğunu anladığım kadarını) buluyorum. İlk örneğinizde JOIN yöntemini kullanmanın avantajları var mı? – mandel

+0

mandel: Evet, uğraştığınız takımlar büyüdükçe avantajlar hızla ortaya çıkıyor. JOIN çok daha iyi ölçeklenebilir. Ancak, bu saatlerde, kesin bir şey söyleyebiliriz sanmıyorum. Bu kadar küçük bir farkı göz ardı ederdim. Ancak, başa çıkmak için daha fazla veri aldığınızda hala büyük farklar görmelisiniz. Alt sorgu çözümü, dış sorgunun her satırı için her bir alt sorguyu yürütür. Yuvalanmış bir döngü birleştirmesi genellikle çok daha verimlidir. –

İlgili konular