2011-04-17 33 views
1

讓我們想象一下,我們有兩個表:用戶(用戶ID,用戶名,UserPhoto)和文章(條款ArticleID,用戶ID,ArticleText)。現在我們執行內部聯接查詢與文章檢索用戶:加入操作重複

SELECT UserId, UserName, UserPhoto, ArticleId, ArticleText 
FROM Users as u INNER JOIN Articles as a ON u.UserId = a.UserId 

查詢結果的結構如下所示:

UserId1 UserName1 UserPhoto1 ArticleId1 ArticleText1 
UserId1 UserName1 UserPhoto1 ArticleId2 ArticleText2 

所以對於第一個用戶,我們有兩篇文章和USERNAME1和UserPhoto1是重複的。那麼如果UserPhoto存儲幾千兆字節的blob呢?

我希望數據庫協議有這樣的情況下,一些優化(可能有些地圖,告訴UserPhoto是第一和第二線等),但我從來沒有見過這個任何註釋。所以,我只是想確保此類優化的存在,我並不需要通過自己

回答

1

1)無論photoblob多少次出現在結果集中,它將被讀取(從磁盤到內存的服務器)只有一次,有建於確保這種情況正在發生優化。

2),但它可以被運輸(從服務器到客戶端)多次,有沒有內置在該優化。

3)最好的解決方案是將它作爲一個存儲過程包裝,返回2個記錄集,然後在clinet代碼中進行連接,這種方法與運行需要兩次往返的2個查詢不同。

4)如果你不想這樣做,你可以獲取用戶的所有文章IDS CSV格式,然後你可以很容易地拆分成CSV文件在客戶端代碼單獨字符串。

下面是示例輸出

UserId UserName UserPhoto CSV_ArticleId    CSV_ArticleText 
------- --------- ---------- ------------------------ ---------------------------- 
UserId1 UserName1 UserPhoto1 ",ArticleId1,ArticleId2" ",ArticleText1,ArticleText2" 
UserId2 UserName2 UserPhoto2 ",ArticleId3"    ",ArticleText3" 

這裏是你如何能做到這一點。測試數據庫上逐字運行代碼,你可以看到結果

CREATE TABLE Users(UserId int , UserName nvarchar(256), UserPhoto nvarchar(256)) 

CREATE TABLE Articles (ArticleId int , UserId int , ArticleText nvarchar(256)) 

INSERT INTO Users(UserId,UserName,UserPhoto) 
VALUES (2,'2a','2pa') 
INSERT INTO Users(UserId,UserName,UserPhoto) 
VALUES (1,'a','pa') 

INSERt INTO Articles (ArticleId, UserId, ArticleText) 
VALUES (2,2,'text2') 
INSERt INTO Articles (ArticleId, UserId, ArticleText) 
VALUES (1,2,'text1') 

;WITH tArticles AS (SELECT ArticleId, UserId, ArticleText FROM Articles) 
SELECT 
    UserId, 
    UserName, 
    UserPhoto, 
    (SELECT TOP 1 LTRIM(
         (SELECT ',' + CONVERT(nvarchar(256),A.ArticleId) FROM Articles A WHERE U.UserId = A.UserId ORDER BY A.ArticleId FOR XML PATH('')) 
         )) as CSV_ArticleId, 
    (SELECT TOP 1 LTRIM(
         (SELECT ',' + CONVERT(nvarchar(256),A.ArticleText) FROM Articles A WHERE U.UserId = A.UserId ORDER BY A.ArticleId FOR XML PATH('')) 
         )) as CSV_ArticleText     

FROM Users U 
2

首先要解決它,創建照片和圖片用戶ID相關聯的第三表。其次,你需要爲了運行兩個單獨的查詢檢索:

  1. 用戶提交
  2. 與特定用戶相關聯的每一篇文章/照片

你會循環每張照片覆蓋所有用戶/照片對,並查詢循環中的文章。

+0

你在談論解決方法(這需要多個數據庫查詢),但我是問所使用的數據庫和它的供應商的解決方案。我只是不相信沒有任何內置的解決方案來解決這種重複 – SiberianGuy 2011-04-18 20:29:19

2

您可以運行兩個查詢,一個獲取用戶數據(所以每張照片將旅遊一次):

SELECT u.UserId 
    , u.UserName 
    , u.UserPhoto 
FROM Users as u 

,另一個是得到了休息(條)數據:

SELECT a.UserId    <--- only UserId this time 
    , a.ArticleId 
    , a.ArticleText 
FROM Users as u 
    INNER JOIN Articles as a 
    ON u.UserId = a.UserId 

最後,使用userids將結果結合到您的應用程序代碼中。

+0

的問題。如果你想確保最佳數據流,你必須運行不同的查詢。如果你有一個BLOB,它會流過它請求的n倍,而不管它們是否相同。 – 2011-04-20 14:53:00

2

你能避免多次獲取照片時是這樣的:

SELECT * FROM (
    SELECT UserId, UserName, UserPhoto, ArticleId, ArticleText 
    FROM Users as u INNER JOIN Articles as a ON u.UserId = a.UserId 
    WHERE ArticleId IN (SELECT MIN(ArticleId) FROM Articles GROUP BY UserId) 
    UNION ALL 
    SELECT UserId, UserName, NULL, ArticleId, ArticleText 
    FROM Users as u INNER JOIN Articles as a ON u.UserId = a.UserId 
    WHERE ArticleId NOT IN (SELECT MIN(ArticleId) FROM Articles GROUP BY UserId) 
) base 
ORDER BY ArticleId; // UserId,ArticleId will also work if you want it sorted by users. 

這僅獲取與第一篇文章中取出的照片,併爲後續文章返回NULL。您的應用程序可以在首次讀取時緩存照片。