数据库模式混乱(索引和约束)

Sky*_*ive 8 mysql sql database schema

我对架构的设计有点困惑,但在开始之前,让我先向您展示架构,

CREATE TABLE Person
(
    PersonID INT NOT NULL PRIMARY KEY,
    FirstName VARCHAR(50),
    LastName VARCHAR(50),
    -- some columns here..
    CONSTRAINT tb_idF INDEX (FirstName),
    CONSTRAINT tb_idL INDEX (LastName)
    -- or 
    -- CONSTRAINT tb_idL INDEX (FirstName, LastName)
    -- other constraints ...
);

CREATE TABLE JobDescription
(
    JobDescriptionID INT NOT NULL PRIMARY KEY,
    JobDescriptionName VARCHAR(50) UNIQUE
    -- some columns here..
    -- constraints ...
);
Run Code Online (Sandbox Code Playgroud)

并且混淆在这里,表的映射表:PersonJobDescription.目前,我有这个设计,

CREATE TABLE Person_JobDescription
(
    RECID INT AUTO_INCREMENT PRIMARY KEY,   -- for some special reasons
                                            -- I need to map to other table
    PersonID INT,
    JobDescriptionID INT,
    StartYear INT,                          -- year JobDescription was Appointed
    EndYear INT,
    CONSTRAINT tb_fk1 FOREIGN KEY (PersonID) 
        REFERENCES Person(PersonID),
    CONSTRAINT tb_fk2 FOREIGN KEY (JobDescriptionID) 
        REFERENCES JobDescription(JobDescriptionID),
    CONSTRAINT tb_uq UNIQUE (PersonID, JobDescriptionID)
);
Run Code Online (Sandbox Code Playgroud)

但我有另外的想法,映射表的哪个结构将是这样的

CREATE TABLE Person_JobDescription
(
    PersonID INT,           -- map these two columns on the other table
    JobDescriptionID INT,   -- ^^
    StartYear INT,          -- year JobDescription was Appointed
    EndYear INT,
    CONSTRAINT tb_fk1 FOREIGN KEY (PersonID) 
        REFERENCES Person(PersonID),
    CONSTRAINT tb_fk2 FOREIGN KEY (JobDescriptionID) 
        REFERENCES JobDescription(JobDescriptionID),
    CONSTRAINT tb_pk PRIMARY KEY (PersonID, JobDescriptionID)
);
Run Code Online (Sandbox Code Playgroud)

当我根据上面的表创建并测试查询时,它们都返回相同的结果,并且性能也与我在小型数据库(具有50k记录)上测试的性能相同.我想知道这两个查询在大型数据库上的表现如何.

质询

  • Person_JobDescription您希望在大型数据库上使用映射表()的两个模式中的哪一个?

按照指示,我不允许UNIQUEFirstName和上创建约束LastName.但我已经提供了两列的索引.

  • 我会在桌上使用什么类型的索引Person?对于每列或用于化合物索引的索引FirstNameLastName
  • 我何时才能使用单一索引INDEX (Col1)INDEX (Col2)结束INDEX (Col1, Col2)

感谢您花时间阅读此问题.

最好的祝福,

德里克弗洛斯

Mik*_*ll' 7

我更喜欢第二种方法.通过使用代理ID号在逻辑上不需要识别时,可以引入更多强制连接.这要求您"在整个数据库中追逐ID号",这是相当于"在整个数据库中追逐指针"的SQL.追逐指针是IMS的特征,IMS是关系模型旨在取代的数据库架构之一.(IMS使用分层架构.)今天重塑它是没有意义的.(虽然很多人都这样做.)

例如,如果您有五个级别的代理ID号,并且您想要一个人的姓名,则必须进行四次连接才能获得它.使用第二种方法,您只需要一次加入.如果您不想编写多列连接,请使用CREATE VIEW并执行一次.

性能很容易测试.只需使用您喜欢的脚本语言生成几百万个随机行,然后将它们加载到测试服务器中.您不仅可以找到性能问题隐藏的位置,还可以在CREATE TABLE代码中找到所有错误.(您的代码不会按原样运行.)了解EXPLAIN,如果您还不知道它.

至于索引,您可以在生成和加载的随机行上测试它.如果用户始终提供名字,则(first_name,last_name)上的多列索引将最有效.但是很多用户不会这样做,而是更喜欢用姓氏搜索.对于喜欢按姓氏搜索的用户,(first_name,last_name)上的多列索引无效.你可以测试一下.

仅仅因为这个原因,如果有两个单独的索引,一个用于名字,一个用于姓氏,则对名字和姓氏进行索引通常会更有效.


什么是追ID号是什么意思?

这个问题的潜在设计模式是"每行必须有一个id号,所有外键都必须引用id号." 在SQL数据库中,它实际上是一种反模式.根据经验,任何可以让你在不考虑密钥的情况下设计表格的模式应该被认为是有罪的,直到被证明是无辜的 - 它应该被认为是一种反模式,直到被证明不是.

create table A (
 a_id integer primary key,
 a_1 varchar(15) not null unique,
 a_2 varchar(15) not null
);

create table B (
  b_id integer primary key
  a_id integer not null references A (a_id),
  b_1  varchar(10) not null,
  unique (a_id, b_1),
);

create table C (
  c_id integer primary key,
  b_id integer not null references B (b_id),
  c_1 char(3) not null,
  c_2 varchar(20) not null,
  unique (b_id, c_1)
);

create table D (
  d_id integer primary key,
  c_id integer not null references C (c_id),
  d_1 integer not null,
  d_2 varchar(15),
  unique (c_id, d_1)
);
Run Code Online (Sandbox Code Playgroud)

如果您需要关于表"D"的报告,并且报告需要

  • 列D.d_1和D.d_2,和
  • 列A.a_1和A.a_2,

你需要3个连接来实现它.(试试吧.)你正在追逐身份证号码.(就像在IMS中追逐指针一样.)以下结构是不同的.

create table A (
 a_1 varchar(15) primary key,
 a_2 varchar(15) not null
);

create table B (
  a_1 varchar(15) not null references A (a_1),
  b_1  varchar(10) not null,
  primary key (a_1, b_1),
);

create table C (
  a_1 varchar(15) not null,
  b_1 varchar(10) not null,
  c_1 char(3) not null,
  c_2 varchar(20) not null,
  primary key (a_1, b_1, c_1),
  foreign key (a_1, b_1) references B (a_1, b_1)
);

create table D (
  a_1 varchar(15) not null,
  b_1 varchar(10) not null,
  c_1 char(3) not null,
  d_1 integer not null,
  d_2 varchar(15),
  primary key (a_1, b_1, c_1, d_1),
  foreign key (a_1, b_1, c_1) references C (a_1, b_1, c_1)
);
Run Code Online (Sandbox Code Playgroud)

使用此结构,同一报表需要单个连接.

select D.d_1, D.d_2, A.a_1, A.a_2
from D
inner join A on D.a_1 = A.a_1;
Run Code Online (Sandbox Code Playgroud)

  • 不,他们不一样.如果您在姓氏上有一个索引而在名字上有一个索引,则dbms可以使用它认为更快的任何一个.无论用户名还是姓氏,用户都可以快速响应.但是,如果用户按名字搜索,{last_name,first_name}上的单个复合索引通常不会被*使用. (2认同)
  • 你从哪里获得额外的连接?额外的键/索引是,但是你只加入一个值,而不是多个值.代理键的真正好处是长寿和弹性,业务类型不需要做太多的事情就可以在没有它们的情况下完全搞乱设计,如果它首先值得做,它将会持续和改变. (2认同)