哪个更有效 - 多行还是多列?
Posted
技术标签:
【中文标题】哪个更有效 - 多行还是多列?【英文标题】:Which is more efficient - Multiple rows or multiple columns? 【发布时间】:2022-01-02 21:29:20 【问题描述】:每个用户在登录时至少会使用此数据 15 次。因此 READ 更为重要。
所以我有两种方法,我知道这是一个菜鸟问题,但我只是对选项感到困惑:
方法 1 多行少列,
id data user
1 task1 1
2 task2 1
3 task3 1
4 task1 7
和方法2 多列单行
id task1 task2 task3 user
1 True True True 1
2 True False False 7
请建议哪种方法最好,一切都很大程度上基于只读。所以我会从字面上获取所有这些来计算一些权限和操作。所以这些会用在用户经常去的一些主要路线上。
【问题讨论】:
方法 2 可能是最糟糕的选择之一,它无法扩展:您必须更改数据库和应用程序只是因为您需要第四个任务......下个月同样的问题,当 5 号任务进来时。 同意但高效的明智之举,对吗?如果我们至少有 100 万用户,那么如果它的第一种方法很容易有 300 万行呢@FrankHeikens 请准确描述您将对数据执行的操作。这将决定哪种数据模型更好。 选项 2 是您真正不想要的。在你犯这个错误之前,很多人都有自己的头痛,然后实施了选项 1。你想不想头痛? PostgreSQL 是一个关系型数据库,采用关系型方法使其工作。如果你不这样做,准备头痛。选项 2 只是没有选项。 请更具体。编写您要针对这些数据模型运行的查询并将它们添加到问题中。这样我们就可以得到答案,而不是开放式的讨论。 【参考方案1】:我认为你在这里做了一些过早的优化。
很少会因为像这样的小型快速查询而导致数据库变慢。当搜索查询行为不端或索引不是最适合工作时,通常会让您受益匪浅。
正如大家所说,方法 2 很糟糕,因为每次要添加新任务时都需要添加列。这是一个糟糕设计的典型危险信号。此外,如果要搜索这些列,还需要在它们上添加索引。
方法 1 是常用的方法,而且效果很好。这个问题的典型问题是当你想基于属性进行搜索时,因为你必须每个属性加入一次,这不会很好地优化。
但是,在这种情况下,既然您说这将在登录时读取,我想这是关于存储与用户相关的用户权限或任务。也许您会选择此数据并将其缓存在会话中,因此只需在登录时获取一次。所以在这种情况下,你应该更关心每个页面上发生的查询,而不是只在登录时发生的查询。
无论如何。方法 1 有一个问题:如果数据不是集群的,并且一个用户的行位于磁盘上表文件的不同页面中,那么每行需要一个 IO。这对于 SSD 来说并不是真正的问题,但很好。
幸运的是,postgres 支持两种避免这种情况的方法:集群扫描和仅索引扫描。
CLUSTER 只是按照您指定的索引顺序对磁盘上的表进行排序。由于无论如何您都需要(用户,任务)上的索引来快速查找用户是否有任务,因此您可以在该索引上进行集群,并且用户的所有行都将位于磁盘上的同一位置,因此只有一个 IO需要获取它们。但是 CLUSTER 会锁定表,因此最好在计划维护期间使用它。如果您的表只有几百万行,并且如果您将 maintenance_work_mem 设置得足够高,则只需几秒钟。
另一种方式是仅索引扫描。如果您在 (user,task) 上有一个索引并且您运行 SELECT user,task WHERE user=... 那么 postgres 将使用仅索引扫描,并且在索引中数据按 (user,task) 排序,这意味着它将执行一次 IO 以获取具有第一行的页面,然后该用户的下一行将随后按索引顺序存储在同一页面上,因此它们已经加载并且访问速度非常快。
注意事项:
由于您没有其他列,我将假设 (user,task) 是唯一的,因为在这种情况下重复是没有意义的。所以这可以是你的主键,你可以删除 id 和关联的索引。如果数据为您提供了一个很好的自然主键,则您不必在每个表上都使用序列。
“task”通常是另一个表的外键。
【讨论】:
以上是关于哪个更有效 - 多行还是多列?的主要内容,如果未能解决你的问题,请参考以下文章