2011-01-30 60 views
5

我經常發現自己正在執行幾個獨立的加入表中。例如,假設我們有表collections,它與photossongs都有獨立的一對一關係,其中N從零到很多。而不是獨立加入多個表,使用單獨的查詢?

現在,假設我們想獲得一個收藏,並且都是其(獨立)相關的照片和歌曲。

我通常會使用這樣的:

SELECT 
    collections.collectionid as collectionid, 
    photos.name as photo_name, 
    songs.name as song_name 

FROM collections 
    LEFT JOIN photos ON collections.collectionid = photos.collectionid 
    LEFT JOIN songs ON collections.collectionid = songs.collectionid 

WHERE collections.collectionid = 14 

當然,左加入一個表,其他兩個表,如果第一個加入M行和N行的第二個結果,給M * N行。這在數據庫流量和性能方面看起來並不理想。

+--------------+------------+-----------+ 
| collectionid | photo_name | song_name | 
+--------------+------------+-----------+ 
| 14   | 'x'  | 'a'  | \ 
| 14   | 'x'  | 'b'  | - Each photo is returned 3 times, 
| 14   | 'x'  | 'c'  |/because 3 songs are returned. 
| 14   | 'y'  | 'a'  | \ 
| 14   | 'y'  | 'b'  | 
| 14   | 'y'  | 'c'  |/
+--------------+------------+-----------+ 

或者,可以執行兩種選擇:兩個單獨的查詢,每個接合collections到一個不同的表,給M + N行:

SELECT 
    collections.collectionid as collectionid 
    song.name as song_name 
FROM collections 
    LEFT JOIN songs on collections.collectionid = songs.collectionid 
WHERE collections.collectionid = 14 

和:

SELECT 
    collections.collectionid as collectionid 
    photos.name as photo_name 
FROM collections 
    LEFT JOIN photos on collections.collectionid = photos.collectionid 
WHERE collections.collectionid = 14 

給出:

+--------------+------------+ +--------------+------------+ 
| collectionid | song_name | | collectionid | photo_name | 
+--------------+------------+ +--------------+------------+ 
| 14   | 'a'  | | 14   | 'x'  | 
| 14   | 'b'  | | 14   | 'y'  | 
| 14   | 'c'  | +--------------+------------+ 
+--------------+------------+ 

我的問題:處理這個問題的最佳方法是什麼?

以上都不是最佳。那麼,有沒有另外一種方法可以產生M + N行,但可以在單個查詢中完成?

+1

在MySQL中,您可以使用`group_concat`爲每個組返回1行。不瞭解性能影響。 – 2011-01-30 23:38:07

+0

謝謝馬丁。哇,時髦。據我所知,這些數據彙總後的結果 - 因此不會改變查詢本身的「M *」性能問題。但是,因爲它減少了行數,所以它應該減少循環的長度,在PHP中稱,調用`mysql_fetch_assoc`。 – 2011-01-30 23:57:37

+0

這就是連接如何在SQL中工作,如果不需要此結果,則幾乎需要2個查詢。 – nos 2011-01-31 18:37:21

回答

5

您的第一個選項(兩個獨立的JOIN)似乎沒有爲您提供非常有用的結果集(因爲兩個輔助表生成半笛卡爾積,並且必須在應用程序代碼中去除重複結果)。

第二個選項(兩個單獨的查詢)是可以的,除非您想將兩個查詢的結果作爲單個集合用於演示目的(例如,通過日期字段將它們排序在一起)。

最好的解決辦法,我想,就是這兩個查詢與UNION ALL合併成一個,產生一個結果,只有行設置你真的想:

SELECT 
    collections.collectionid as collectionid, 
    photos.name as photo_name, 
    'photo' as document_type 
FROM collections 
    LEFT JOIN photos on collections.collectionid = photos.collectionid 
WHERE collections.collectionid = 14 
UNION ALL 
SELECT 
    collections.collectionid as collectionid, 
    song.name as photo_name 
    'song' as document_type 
FROM collections 
    LEFT JOIN songs on collections.collectionid = songs.collectionid 
WHERE collections.collectionid = 14 

這種結果集的可ORDERed BY跨越整個組合記錄的任何字段,允許(例如)獲取附加到集合的最近20個文檔,而不管它們是什麼類型。

0

看起來照片和權限之間的關係是未定義的,這會導致您提到的交叉連接。是的,從表面上看,做兩個查詢比你擁有的要好。然而,真正的問題是爲什麼照片和權限沒有基於關鍵的關係?

但也許我不理解你的整體架構。也許所有的權限都屬於單個用戶。如果是的話,那麼我會考慮將所有權限放在一行(多列或者一個XML blob)中,而不是多行。這樣做將允許單個查詢獲取所有值而不會導致無意的交叉連接。

相關問題