【问题标题】:mySQL KEY Partitioning using three table fields (columns)使用三个表字段(列)的 mySQL KEY 分区
【发布时间】:2009-12-21 12:07:52
【问题描述】:

我正在编写一个数据仓库,使用 MySQL 作为后端。我需要根据两个整数 ID 和一个名称字符串对表进行分区。我已阅读(部分)有关分区的 mySQL 文档,在这种情况下,最合适的分区方案似乎是 HASH 或 KEY 分区。

我选择了 KEY 分区,因为我(退出并且)不想负责为我的字段提供“无冲突”哈希算法 - 相反,我依靠 MySQL 哈希来生成哈希所需的密钥.

我在下面包含了我想根据以下字段的 COMPOSITE 分区的表架构的 sn-p:

学校 id、course_id、ssname(学生姓氏)。

顺便说一句,在有人指出这不是存储学校相关信息的最佳方式之前,我必须指出,我只是将下面的案例用作我试图建模的类比。

我当前的 CREATE TABLE 语句如下所示:

CREATE TABLE foobar (
    id         int UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
    school_id  int UNSIGNED NOT NULL,
    course_id  int UNSIGNED NOT NULL,
    ssname     varchar(64) NOT NULL,

    /* some other fields */

    FOREIGN KEY (school_id) REFERENCES school(id) ON DELETE RESTRICT ON UPDATE CASCADE,

    FOREIGN KEY (course_id) REFERENCES course(id) ON DELETE RESTRICT ON UPDATE CASCADE,

    INDEX idx_fb_si (school_id),
    INDEX idx_fb_ci (course_id),
    CONSTRAINT UNIQUE INDEX idx_fb_scs (school_id,course_id,ssname(16))
) ENGINE=innodb;

我想知道如何修改上面的语句,以便使用我在本问题开头提到的三个字段(即 - school_id、course_id 和学生姓氏的起始字母)对表进行分区。

我想问的另一个问题是:

在“边缘”情况下会发生什么,例如,如果我尝试插入一条包含有效* school_id、course_id 或姓氏的记录(不存在基础分区表文件),mySQL 是否会自动创建基础文件。?

举个例子。我有以下学校:纽约幼儿园、贝尔法斯特小学和以下课程:无限维度中的李代数、纠缠实体

还假设我有以下学生(姓氏):布什、布莱尔、侯赛因

当我添加一所新学校(或课程,或学生)时,我可以将它们插入到 foobar 表中(实际上,我想不出为什么不这样做)。我问的原因是我预计会增加更多的学校和课程等,这意味着 mySQL 将不得不在后台创建额外的表(因为哈希会生成新的键)。

如果有这方面经验的人能够确认(最好有支持他们断言的链接),我将不胜感激(即,如果我将新学校、课程或学生添加到数据库中,则不需要手动管理)是正确。

我不知道我的第二个问题是否格式正确(清晰)。如果没有,我很乐意进一步澄清。

*VALID - 有效,我的意思是它在不破坏参照完整性方面是有效的。

【问题讨论】:

  • 您希望通过使用分区获得什么?

标签: mysql database-design data-modeling database-partitioning


【解决方案1】:

我怀疑分区是否像您想象的那样有用。也就是说,您所要求的还有一些其他问题(注意:此答案的全部内容适用于 MySQL 5;版本 6 可能会有所不同):

  • KEY 分区中使用的列必须是主键的一部分。 school_idcourse_idssname 不是主键的一部分。
  • 更一般地说,每个 UNIQUE 键(包括主键)必须包括 partition1 中的所有列。这意味着您只能在 UNIQUE 键中的列的交集上进行分区。在您的示例中,交叉点是空的。
  • 大多数分区方案(KEY 除外)都需要整数或空值。如果不为 NULL,ssname 将不是整数值。
  • 不能同时支持外键和分区2。这是不使用分区的有力论据。

幸运的是,无冲突散列是您无需担心的一件事,因为分区会导致冲突(否则,每个分区中只有一行)。如果您可以忽略上述问题以及limitations on functions used in partitioning expressions,您可以创建一个 HASH 分区:

CREATE TABLE foobar (
    ...
) ENGINE=innodb
  PARTITION BY HASH (school_id + course_id + ORD(ssname))
  PARTITIONS 2
;

应该起作用的是:

CREATE TABLE foobar (
    id         int UNSIGNED NOT NULL AUTO_INCREMENT,
    school_id  int UNSIGNED NOT NULL,
    course_id  int UNSIGNED NOT NULL,
    ssname     varchar(64) NOT NULL,

    /* some other fields */

    PRIMARY KEY (id, school_id, course_id),
    INDEX idx_fb_si (school_id),
    INDEX idx_fb_ci (course_id),
    CONSTRAINT UNIQUE INDEX idx_fb_scs (school_id,course_id,ssname)
) ENGINE=innodb
      PARTITION BY HASH (school_id + course_id)
      PARTITIONS 2
;

或:

CREATE TABLE foobar (
    id         int UNSIGNED NOT NULL AUTO_INCREMENT,
    school_id  int UNSIGNED NOT NULL,
    course_id  int UNSIGNED NOT NULL,
    ssname     varchar(64) NOT NULL,

    /* some other fields */

    PRIMARY KEY (id, school_id, course_id, ssname),
    INDEX idx_fb_si (school_id),
    INDEX idx_fb_ci (course_id),
    CONSTRAINT UNIQUE INDEX idx_fb_scs (school_id,course_id,ssname)
) ENGINE=innodb
      PARTITION BY KEY (school_id, course_id, ssname)
      PARTITIONS 2
;

至于存储表格的文件,MySOL 会创建它们,尽管它可能会在您定义表格时创建它们,而不是在向其中插入行时创建。您无需担心 MySQL 如何管理文件。请记住,分区数量是有限的,在您创建表时由PARTITIONS *n* 子句定义。

【讨论】:

  • 非常丰富的答案。谢谢你。你解决了我所有的担忧。我考虑实现分区的原因是我可能要处理的(几乎是荒谬的)行数。在最后的粗略计算中,我们谈论的是表格中 1.5 亿行以北的数字。如果您仍然认为分区在这种情况下无济于事,我想知道您的原因。 BTW,表已经是4NF了,所有字段都是必填项,在db设计方面没有进一步优化。
  • 分区的问题在于它通常没有帮助。有些查询仍然需要查询每个分区(基本上,这是当您根据分区键的一部分进行过滤时,例如,如果您要在上述分区方案下过滤school_id 而不是course_id 上的查询)。索引将有助于查询优化(分区方案和索引都比表模式更重要)。并不是说您不应该使用分区,但外键可能更有价值。
  • outis:不会出现您描述的场景,因为我将始终使用三个字段进行搜索。事实上,在考虑使用分区之前,我实际上是在考虑使用名为 info_[sid]_[cid]_ssn_records 的物理分离表。然后我意识到分区是一个更优雅的解决方案。如果有什么我忽略了,如果你能在我踏上这条路之前指出我的疏忽,我将不胜感激。
  • outis:实际上,我刚刚重读了您的上一篇文章,其中您说“...但是外键可能更有价值...”。然后,我检查了您提出的 CREATE TABLE 语句,并注意到 FK 已消失。这是疏忽吗? - 或者我是否推断用于分区的字段可能不是另一个表的 FK?
  • 至于分区并不总是有帮助,它还取决于您对字段设置的限制。只有当查询不可能返回分区中的任何行时,才会跳过分区;如果它可能包含一行,则该分区将包含在查询中。然而,索引可以帮助限制查询将扫描的行数,甚至可以完全跳过扫描。查询优化器可以使用索引键前缀; (school_id, course_id, ssname) 上的唯一键可以帮助在 school_id, course_id 但不是 course_id, ssname 上过滤的查询。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-20
相关资源
最近更新 更多