mySQL KEY使用三个表字段(列)进行分区

时间:2009-12-21 12:07:53

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

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

我已经选择了KEY分区,因为我(小伙子)并不想负责为我的字段提供“无冲突”散列算法 - 相反,我依靠MySQL散列来生成散列所需的密钥

我在下面列出了一个表格架构的片段,我希望根据以下字段的COMPOSITE进行分区:

school id,course_id,ssname(student surname)。

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

My Current 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和学生姓氏的起始字母)对表进行分区。

我想问的另一个问题是:

在'edge'情况下会发生什么,例如,如果我尝试插入包含有效* school_id,course_id或surname的记录 - 没有底层分区表文件 - mySQL会自动创建底层文件。

例证。我有以下学校:纽约Kindergaten,贝尔法斯特小学和以下课程:信息维度中的李代数,纠缠实体

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

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

如果在此领域有经验的人能够确认(最好有支持他们断言的链接),我将不胜感激,我的理解(即如果我将新的学校,课程或学生添加到数据库中,则无需人工管理),正确的。

我不知道我的第二个问题是否形成得很好(清楚)。如果没有,我将很乐意进一步澄清。

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

1 个答案:

答案 0 :(得分:2)

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

  • KEY分区中使用的列必须是主键的一部分。 school_idcourse_idssname不属于主键。
  • 更一般地说,每个UNIQUE键(包括主键)必须包含分区1中的所有列。这意味着您只能在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*子句创建表时,会定义有限数量的分区。