只有ID和许多联结表的表

时间:2013-05-09 10:08:23

标签: sql database symfony doctrine normalization

我正在尝试设计一个尽可能可扩展的数据库,所以我用一个简单的场景来测试这个概念。

假设我有contact表。联系人通常包含addressphone numbermobile numberemail address

单个表可以保存此信息。但是,如果联系人有多个这些细节,该怎么办?我的解决方案是使用如下的联结表:

contact -* contact_address *- address
contact -* contact_phone *- phone
contact -* contact_mobile *- phone
contact -* contact_emailaddress *- emailaddress

这将允许我获取有关联系人的所有信息。 此外,addressphoneemailaddress表格成为数据库,用于从分析到简单重复使用数据。

但是,我还不知道这对性能有什么影响,以及这是否是一种好的做法,主要是因为contact表只会保留id而不是其他内容。

一个注意事项是,这使用doctrine2,使用symfony2,因此编写长查询不会成为一个问题,我主要担心的是上面的问题,这已经从一个表跳到了八个,而联系人只是我需要使用的一个区域像这样的模式。

3 个答案:

答案 0 :(得分:1)

使用起来非常好,你根本不用担心。

唯一的问题是如果你允许Doctrine延迟加载关系。例: 如果你

$contact = $repository->find(1) ;

以及稍后在模板中执行类似

的操作
{% for email in contact.emails %}
{{ email.address }}
{% endfor %}

此代码将触发另一个SELECT语句。现在,如果您显示每页10个联系人,则表示将执行额外的10个查询。

如果您显示地址或电话号码等其他内容,请进行数学运算。

要避免这种延迟加载,您需要在查询中加入它们。像

// ContactRepository

public function findForSomePage()
{
    return $this->createQueryBuilder("o")
       ->leftJoin("o.addresses", "a")->addSelect("a")
        .... other joins ...
        ->getQuery()
        ->getResult()
}

现在,您需要显示的所有内容都在1个查询中提取。

答案 1 :(得分:0)

如果联系人有多个地址,您就不会使用联结表,只需使用地址中的外键即可联系。

我希望这种设计很可能更具性能,但需要考虑很多因素。

如果地址可以附加到多个联系人,并且联系人可以有多个地址,那么您将使用联结表。

答案 2 :(得分:0)

使用表继承。

单表继承示例:

create table address_type(
  id char(1) primary key,
  description text not null unique
);

insert into address_type values
('t', 'Telephone Number'),
('e', 'E-mail Address'),
('m', 'Mailing Address'),
('w', 'Web Address');

create table address_role(
  id char(1) primary key,
  description text not null unique
);

insert into address_role values 
('f','Fax'),
('m','Mobile'),
('h','Home'),
('w', 'Work');

create table address(
  id serial primary key,
  type char(1) not null references address_type(id),
  telephone_number varchar(15) null,
  email_address varchar(320) null,
  web_address varchar(2083) null,
  suite_or_apartment text null,
  city_id bigint null references city(id),
  postal_area_id bigint null references postal_area(id)
);

create table party(
  id serial primary key,
  name varchar(255) not null
);

create table party_address(
  party_id bigint not null references party(id),
  address_id bigint not null references address(id),
  from_date date not null default current_date,
  to_date date null,
  role char(1) null references address_role(id),
  telephone_extension varchar(5) null,
  primary key (party_id, address_id, from_date)
);