使用三个表字段(列)的mySQL键分区

使用三个表字段(列)的mySQL键分区,mysql,database-design,data-modeling,database-partitioning,Mysql,Database Design,Data Modeling,Database Partitioning,我正在编写一个数据仓库,使用MySQL作为后端。我需要根据两个整数ID和一个名称字符串对一个表进行分区。我已经阅读了有关分区的mySQL文档(部分),在这种情况下,最合适的分区方案似乎是哈希或键分区 我之所以选择密钥分区,是因为我(退缩了,不想负责为我的字段提供“无冲突”哈希算法——相反,我依靠MySQL哈希生成哈希所需的密钥 我在下面包含了一个表的模式片段,我想基于以下字段的组合对其进行分区: 学校id、课程id、学校名称(学生姓氏) 顺便说一句,在任何人指出这不是存储学校相关信息的最佳方式之

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

我之所以选择密钥分区,是因为我(退缩了,不想负责为我的字段提供“无冲突”哈希算法——相反,我依靠MySQL哈希生成哈希所需的密钥

我在下面包含了一个表的模式片段,我想基于以下字段的组合对其进行分区:

学校id、课程id、学校名称(学生姓氏)

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

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

我想问的另一个问题是:

在“边缘”情况下会发生什么?例如,如果我试图插入一个包含有效*学校id、课程id或姓氏的记录,mySQL会自动创建基础文件吗

这是一个很好的例子。我有以下学校:纽约幼儿园,贝尔法斯特小学和以下课程:弱维李代数,纠缠实体

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

当我添加一个新学校(或课程,或学生)时,我可以将它们插入到foobar表中吗(实际上,我不认为为什么不可以)。我问这个问题的原因是我希望添加更多的学校和课程等,这意味着mySQL必须在幕后创建额外的表(因为散列将生成新的键)

如果在这方面有经验的人能够确认(最好有支持其主张的链接),我的理解(即,如果我向数据库中添加新学校、课程或学生,则无需手动管理)是正确的,我将不胜感激

我不知道我的第二个问题是否结构合理(清楚)。如果没有,我很乐意进一步澄清


*VALID——我所说的VALID是指它在不破坏引用完整性方面是有效的

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

  • 键分区中使用的列必须是主键的一部分
    school\u id
    course\u id
    ssname
    不是主键的一部分
  • 更一般地说,每个唯一键(包括主键)必须包括分区中的所有列。这意味着您只能在唯一键中的列的交点上进行分区。在您的示例中,交叉点为空
  • 大多数分区方案(键除外)需要整数值或空值。如果不为NULL,
    ssname
    将不是整数值
  • 外键和分区不同时受支持。这是不使用分区的有力论据
幸运的是,无冲突散列是您不必担心的一件事,因为分区将导致冲突(否则,每个分区中只有一行)。如果可以忽略上述问题以及,则可以使用以下内容创建哈希分区:

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
;
或:


至于存储表的文件,MySOL将创建它们,尽管它可能在定义表时创建,而不是在插入行时创建。您不必担心MySQL如何管理文件。请记住,分区的数量是有限的,当您通过
partitions*n*
子句创建表时会定义分区。

您希望通过使用分区获得什么?非常有用的答案。谢谢你,奥蒂斯。你解决了我所有的问题。我之所以考虑实现分区,是因为我可能要处理的行数(几乎可笑)。在最后一次粗略统计时,我们讨论的是表中以北1.5亿行的数字。如果您仍然认为分区在这种情况下没有帮助,我想知道您的原因。顺便说一句,表已经在4NF中,所有字段都是必需的,在db设计方面没有进一步的优化。分区的问题是它通常没有帮助。有些查询仍然需要查询每个分区(基本上,这是在根据分区键的一部分进行筛选时进行的,例如,如果要在上述分区方案下筛选
school\u id
上的查询,而不是
course\u id
)。索引将在查询优化中发挥更大的作用(分区方案和索引都是查询问题,而不是表模式)。并不是说不应该使用分区,但是外键可能更有价值。outis:您描述的场景不会出现,因为我将始终使用这三个字段进行搜索。事实上,在考虑使用分区之前,我实际上是在考虑使用名为info\uSID]\uCID]\uSSN\uRecords的物理上独立的表。然后我意识到分区是一个更优雅的解决方案。如果有什么我忽略了,在我走这条路之前,如果你能指出我的疏忽,我将不胜感激。奥蒂斯:事实上,我刚刚重读了你的上一篇文章,你在文章中说“……但是外键可能更有价值……”。然后我检查了CREATE T
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
;