这是一个关于数据库访问性能与代码简单性和害虫做法的问题。
假设我有一个Users
表和一个Addresses
表。每个用户可以有多个地址,这些地址将存储在Addresses
表中,其中包含Users
表的外键。
假设我总是想与用户一起获取地址,从数据库中读取用户的最佳方法是什么?
第一种选择是查询用户,比如通过他的用户名,一旦我有了对象,就使用用户的 id 在Addresses
表中查询所有用户的地址。
优点:
- 简单代码
- 不传输重复数据
缺点:
- 需要对数据库进行两次查询
第二种选择是编写一个查询,该查询将Users
与Addresses
联接,并为用户拥有的每个地址返回用户结果行。除address
列外,所有列对于每一行都完全相同。然后,我将所有行聚合到一个带有地址列表的user
对象中。
优点:
- 需要对数据库进行单个查询
缺点
- 相对复杂的代码(聚合用户)
- 传输的大量数据是多余的
这是我能想到的两种方式,都有其优点和缺点。您会建议哪个选项?
也许完全是另一种解决方案?
我的第一条经验法则是让数据库引擎做它擅长的事情。表的连接是数据库以最高效率执行的基本功能。数据库的加入将始终比通过进行多个调用可以执行的操作更快。
只有当您在数据传输方面遇到实际问题或数据非常庞大时,您提出的关于它获取大量用户数据这一事实的观点才是正确的。 作为交换,您只对数据库进行一次调用,而不是多次调用。这种节省可以远远超过数据大小的可能缺点。
我不太确定您所说的"聚合用户数据"是什么意思,因为您只是从该用户的第一个条目中获取它并跳过其余条目。
归根结底,让数据库完成它的工作,除非有很好的理由不这样做。
在非常严重的情况下,有一些方法可以在用户数据中引入除第一行之外的所有空值。但是,这使SQL查询变得非常复杂,并且通常不值得开销。
我刚刚在GitHub上与Microsoft进行了长时间的辩论,并与MS-SQL MVP进行了讨论。
总结该线程(来自我的规范):
对于 SQL Server,- 无论是单个查询还是 10 个查询都无关紧要,返回的冗余字段对 SQL Server 的影响为 0。
- 无论如何,拆分查询是SQL在内部所做的,当人们尝试优化SQL时,通常是最糟糕的,因为SQL在不强制它以特定方式运行时做得更好。
- 具有多个查询会对 SQL 产生开销。
- 实际拆分查询唯一解决的是网络上的带宽,因为通过网络传输的字节会更少,他说与有多个查询相比,这可以忽略不计。
- 当您有大量返回的行时,由于表假脱机和带宽的原因,您需要拆分查询。
最后,我决定使用
GROUP_CONCAT(DISTINCT addresses.address SEPARATOR ' | ') addresses
...
GROUP BY userId
然后,我将地址拆分为客户端中的列表(特别是在我的客户BeanPropertyRowMapper
中)