我们正在创建一个(可能)庞大的数据库,该数据库将填充Users
。每个用户都可以创建许多Items
。应用程序稍后将根据他们的请求为公众提取并列出这些项目。每个Item
都会有一个指针指向其创建者的UserID
。提取项目时,用户的姓名和图片(网址)也必须始终。
考虑到成千上万用户的可能性,每个用户都有数十个项目,除了成千上万的项目请求之外,我会想象每次查询用户和项目都有点多,即使它是一个单一查询。由于在没有用户用户名的情况下永远不会获取项目本身,在项目中存储用户名用户是否完全不合理? e.g:
(原始方式的简单表示)
Table(User):UserID, Username, UserPictureURL, Email, Address, ...
Table(Item):ItemID, ItemName, Value, UserID, ...
此处项的查询始终例如Select * from User, Item Where..
。这将从两个表中获取元素。
(思想方式的简单表示)
Table(User):UserID, Username, UserPictureURL, Email, Address, ...
Table(Item):ItemID, ItemName, Value, UserID, Username, UserPictureURL ...
查询现在只需要Select * from Item
。只有一张桌子上的元素。
鉴于User表包含数十万用户,甚至更多,通过访问每个项目查询的两个标签会损失多少性能/速度?我知道两次存储值是错误,并且存在关系数据库的唯一目的是消除这种情况,但是如果请求时间长度明显减少那么它是如此糟糕?如果我们要获取一个项目,但有100,000个用户,是否需要一些额外的时间来查询?即使在同一个查询中,也是第一个例子。
我一直在做一些简单的数学计算。如果我们将用户名的最大长度设置为30个字符,将pictureURL设置为80,那么110个字符可能会被“双重存储”。鉴于有100,000个用户,每个有3个项目,I.E 300,000双重存储,这将导致总共额外增加~31.5兆字节。这对于更快的请求来说是一个很小的代价。
我意识到如果我们允许用户更改用户名,或者当他们更改个人资料图片时,我们就必须遍历所有项目并在那里更改,但我仍然 >撕裂。用户名/图片的更改可以异步发生,并且显着比项目请求更少
。我不确定这是关于意见的问题,还是有任何支持这两种方法的事实。
编辑:我看到人们提到数十万条目并不是那么多。为了相当乐观,让我们说可以扩展到数十亿。它会改变什么吗?
答案 0 :(得分:4)
真正了解性能的唯一方法是使用您的数据在系统上进行测试。
然而,几十万行并不是那么多行。而且,规范化系统使用简单的连接设法一直获取数据:
select ui.*
from users u join
useritems ui
on u.userid = ui.userid
where u.username = XXX;
假设您在useritems(userid)
上有索引,我希望此查询能够为您的任务执行相当充分的操作。无需在两个表中复制username
。
对于可变长度字符串,在数字id(我假设userid
将是)的索引上也有一个优点。整数的索引会更小。这意味着当索引在内存中时,更多内存可用于其他查询。
答案 1 :(得分:2)
您的问题是关于规范化和非规范化数据库。
在非标准化数据库中(如带有1个表的示例),数据正在重复。实际上只有一种方案不存在问题:如果您知道您永远不会更新或删除数据,只会在其中插入新数据。如果您更新或删除非标准化数据库中的数据,则存在“更新异常”的风险。
非标准化数据库速度稍快,这就是它在数据仓库中使用的原因。但是,在您给出的示例中,即使表格确实变得非常大,这根本不应该是一个问题。