【问题标题】:Mysql : multiple tables or one big table?Mysql:多表还是一张大表?
【发布时间】:2012-11-28 09:43:00
【问题描述】:

这个问题已经被问过了,但我没有找到“1 个语音答案”。

这样做更好吗:

  • 一张大桌子:

user_id |属性_1 |属性_2 |属性_3 |属性_4

  • 或 4 个小表,其中: 用户 ID |属性_1

user_id |属性_2

user_id |属性_3

user_id |属性_4

一张大桌子还是许多小桌子?每个用户只能有 1 个属性 X 值。我们有很多数据要保存(1 亿用户)。我们正在使用 innoDB。性能对我们来说非常重要(10 000 次查询/秒)。

谢谢!

弗朗索瓦

【问题讨论】:

  • 这取决于您想对数据做什么,但从您的描述来看,两者都不是最佳的。相反,您可以拥有一个包含以下内容的表:user_id、attribute_num、attribute——因此,由于每个用户只有一个attribute_X 值,因此这仅涵盖了可以索引的3 个字段中的所有内容。对于某些特定任务,这可能不是最好的选择,但同样取决于您想要什么。
  • 你需要问自己的问题是,你通常需要在同一个查询中为同一个用户获取多个属性吗?如果您有多个并且它们位于不同的表中,那么由于需要表连接,性能会变慢。
  • @sn00k4h 我们通常只进行原子选择/更新(出于缓存原因,当时只有一个属性)。因此,为了询问 10 个属性,我们进行了 10 个调用(但可能只有 1 个或 0 个请求,具体取决于缓存状态)。
  • @Ynhockey 我们不能使用 "user_id, attribute_num, attribute" 因为属性字段可以是 int、bigint、date、float 等...
  • 尝试以您提到的方式优化缓存命中可能会或可能不会真正提高您的性能,具体取决于各种因素。如果我是你,我会尝试不同的可能设计并比较性能,因为这是你(更)确定的唯一方法。不同数据集的相同设计可以执行非常不同的操作。您可以尝试的另一种可能的设计是两种方式的混合 - 将具有相对较小数据类型(例如:int、date)的“属性”放在同一个表中,并将较大的数据类型分开。

标签: mysql performance optimization innodb


【解决方案1】:

如果您遵守 零、一或多 原则,即没有这样的东西、其中之一或无限数量,您将始终构建适当的规范化表来跟踪诸如这个。

例如,一个可能的架构:

CREATE TABLE user_attributes (
  id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
  user_id INT NOT NULL,
  attribute_name VARCHAR(255) NOT NULL,
  attribute_value VARCHAR(255),
  UNIQUE INDEX index_user_attributes_name(user_id, attribute_name)
);

这是基本的键值存储模式,您可以在其中为每个用户拥有许多个属性。

虽然这种存储要求比固定列排列的存储要求更高,如 attribute1 这样总是令人沮丧的名称,但在 TB 大小的硬盘驱动器时代,成本已经足够低,几乎不会成为问题。

通常,您会为此数据创建一个表,直到插入时间成为问题。只要您的插入速度很快,我就不会担心。此时,您可能需要考虑一种 分片 策略,将这些数据划分为具有相同架构的多个表,但前提是必须这样做。

我想这将处于大约 10-5000 万行阶段,但如果此表中的插入活动量相对较低,则可能会更高。

不要忘记优化读取活动的最佳方法是使用缓存:最快的数据库查询是您不进行的查询。对于这类事情,您通常会使用 memcached 之类的东西来存储先前提取的结果,并且您会在写入时使其无效。

与往常一样,在生产规模上对任何提议的架构进行基准测试。

【讨论】:

  • 您好,感谢您的回答。问题是我们对属性值(排序、过滤等)提出了请求,每个属性都可以不同(日期、整数、大整数、浮点数)。所以我们不能使用 Varchar 来存储属性数据。
  • 如果你有一个固定的模式,然后创建具有适当类型的列,每个用户一条记录。您使用attribute1 等的示例是某些应用程序的典型特征,这些应用程序实际上就是该列的名称。您正在做的事情听起来会崩溃,除非您在顶部使用某种搜索引擎(例如 Sphinx)以减轻服务器的压力。 MySQL 需要索引具有高性能,但大而复杂的索引会减慢插入时间。
  • 这种键值方法的一种变体是有多个值表,每种类型一个,您需要从所有值表中进行选择并将它们组合在一起。将为特定的 attribute_nameattribute_nameuser_id 组合设置索引。
  • 如果你真的想扩展它,你可能需要某种 map-reduce 层来将查询分散到 N 个数据库实例中。如果您这样做,您希望您的表格尽可能简单和通用。请记住,从大表中删除列非常困难,但删除代表列的表更容易。我不确定您将如何针对您的特定情况进行处理,因为不清楚您是在谈论假设用户还是实际用户。
  • 我们谈论的是实际用户,我们知道将列添加到大型数据库是非常困难的问题,这就是为什么我们正在考虑更改为非常小的表但我们真的不知道它是否是一个好主意与否
【解决方案2】:

1 大桌子: 用户 ID |属性_1 |属性_2 |属性_3 |属性_4

将使您的管理更轻松。否则,单独的查找过多,这也会使针对数据库的编程变得复杂,并有可能增加应用程序错误。

【讨论】:

    猜你喜欢
    • 2014-01-31
    • 2012-04-04
    • 1970-01-01
    • 2020-03-25
    • 2013-03-05
    • 2012-12-15
    • 2011-03-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多