假设我们有两个表:Users(UserId,UserName,UserPhoto)和Articles(ArticleId,UserId,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对于第一行和第二行是相同的)但我从未遇到任何关于此的注释。所以我只想确保存在这种优化,我不需要自己解决它
答案 0 :(得分:2)
首先,为Photos创建第三个表,并将UserId与Photo关联。其次,您需要运行两个单独的查询才能检索:
您将遍历所有用户/照片对,并查询循环内的文章。
答案 1 :(得分: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
最后,使用用户ID将结果合并到应用程序代码中。
答案 2 :(得分: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。您的应用程序可以在首次阅读时缓存照片。
答案 3 :(得分:1)
1)无论photoblob在结果集中出现多少次,它都会被读取(从服务器中的磁盘到内存),内置优化以确保发生这种情况。
2)然而,它可以多次传输(从服务器到客户端),没有内置的优化。
3)最好的解决方案是将此包装为一个返回2个记录集的存储过程,并在clinet代码中进行连接,这种方法不同于运行需要两次往返的2个查询。
4)如果您不想这样做,您可以以CSV格式获取用户的所有文章ID,然后您可以轻松地将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