5

以下加入应该为具有特定状态的用户检索用户信息及其消息:

SELECT * FROM user, message WHERE message.user_id=user.id AND user.status=1

问题是结果集中有关某个用户的所有行都包含重复有关该用户的相同数据的冗余列(从用户表中检索的那些字段),只有消息表中的字段包含非冗余信息。像这样的东西:

user.id  username email            message.id  subject
1        jane     jane@gmail.com   120         Notification 
1        jane     jane@gmail.com   122         Re:Hello 
1        jane     jane@gmail.com   125         Quotation
2        john     john@yahoo.com   127         Hi jane
2        john     john@yahoo.com   128         Fix thiss 
2        john     john@yahoo.com   129         Ok
3        jim      jim@msn.com      140         Re:Re:Quotation

正如您所看到的,许多数据是多余的,我们不想先找到用户,然后在类似结构或类似结构的循环中处理他们的消息。应该不惜一切代价避免导致微查询的循环。

我不关心我的程序的输出,它在 UI 中得到了很好的处理。我认为,如果我能够设法消除与该用户相关的所有行中用户数据的重复,则返回此查询结果产生的网络流量可能会大大减少。

4

4 回答 4

3

您应该知道几件事。

首先是默认的 SQL JOIN 构造本质上是一个集合叉积,受 WHERE 子句的限制。这意味着它是乘法的——你会得到重复的结果,然后将其修剪掉。您还必须小心存在 NULL 字段。

第二个是有一个'DISTINCT'关键字。当您在选择中的一列添加前缀时,您将在结果中最多获得该列的某个值的一个实例。因此,根据您的查询,“SELECT DISTINCT user.id FROM”将消除服务器端的冗余。

第三是解决这个问题的正确方法很可能是不使用*操作符。我建议:

SELECT user.id,username,email,subject FROM message m,user WHERE m.user_id=user.id AND user.status=1

这使用简单、易于理解的隐式连接语法,并且在任何服务器上都应该是有效的 SQL。我可以保证它至少可以与 MySQL 一起工作。它还将“消息”表别名为“m”作为简写。

如您所料,这将减少从 SQL 服务器到数据库的流量。

编辑:如果您想消除“冗余”电子邮件信息,则不能 - 您必须进行两个不同的查询。SQL 结果是表格,必须是矩形的,填充了所有已知值。没有“同上”条目。

编辑 2:您只需要进行两个查询。例如:

SELECT subject FROM message WHERE message.id IN (SELECT user.id FROM user WHERE status=1)

这是一个包含嵌套查询的查询,因此它确实会产生两次数据库命中。但它没有任何程序循环。

于 2010-07-05T05:34:09.200 回答
1

在直接的 sql 查询中,如果您将它们保留为单个查询,则没有。如果您以编程方式将其打印出来,那么您将按用户 ID 排序,并且仅在用户 ID 更改时才重新打印该信息。

于 2010-07-05T04:48:57.817 回答
1

在 SQL 标准中,您将使用 NATURAL JOIN;这将连接常见的列名,并且只保留这些常见名称的一份副本。

在实践中,您会仔细列出所需的列,而不是使用“*”速记符号。

于 2010-07-05T04:58:41.133 回答
0

假设您可以使用存储过程,您可以编写一个来运行上述查询,然后使用游标存储“冗余信息”的空值以获得类似

user.id  username email            message.id  subject 
1        jane     jane@gmail.com   120         Notification  
null     null     null             122         Re:Hello  
null     null     null             125         Quotation 
2        john     john@yahoo.com   127         Hi jane 
null     null     null             128         Fix thiss  
null     null     null             129         Ok 
3        jim      jim@msn.com      140         Re:Re:Quotation

然后将此结果集返回到临时表中。但这可能会减少网络流量,但会增加处理开销

另一种方法是运行 2 个查询,一个获取用户信息,另一个获取仅包含链接用户 ID 的消息信息,然后使用应用程序服务器端代码执行“加入”。就像是

SELECT DISTINCT user.* FROM user, message WHERE message.user_id=user.id AND user.status=1

SELECT user.id, message.* FROM user, message WHERE message.user_id=user.id AND user.status=1

这将导致 2 次访问数据库,而不是 1 次,即使网络流量减少,最终可能会更慢。

另一种方法是将这两个捆绑到一个结果集中,例如

SELECT user.* FROM user, message WHERE message.user_id=user.id AND user.status=1
UNION ALL
SELECT user.id, message.* FROM user, message WHERE message.user_id=user.id AND user.status=1

得到类似的东西

   user.id  username/message.id    email/subject 
    1        jane                   jane@gmail.com   
    2        john                   john@yahoo.com   
    3        jim                    jim@msn.com      
    1        120                    Notification           
    1        122                    Re:Hello           
    1        125                    Quotation          
    2        127                    Hi jane          
    2        128                    Fix thiss           
    2        129                    Ok          
    3        140                    Re:Re:Quotation

然后使用应用程序服务器逻辑将其分离出来。减少了网络流量,但增加了应用程序服务器负载/略微增加了数据库服务器负载。

但是节省的网络流量很少值得增加复杂性。

于 2010-07-05T05:59:47.923 回答