我正在尝试设计一个尽可能可扩展的数据库,所以我用一个简单的场景来测试这个概念。
假设我有contact
表。联系人通常包含address
,phone number
,mobile number
和email address
。
单个表可以保存此信息。但是,如果联系人有多个这些细节,该怎么办?我的解决方案是使用如下的联结表:
contact -* contact_address *- address
contact -* contact_phone *- phone
contact -* contact_mobile *- phone
contact -* contact_emailaddress *- emailaddress
这将允许我获取有关联系人的所有信息。
此外,address
,phone
和emailaddress
表格成为数据库,用于从分析到简单重复使用数据。
但是,我还不知道这对性能有什么影响,以及这是否是一种好的做法,主要是因为contact
表只会保留id
而不是其他内容。
一个注意事项是,这使用doctrine2,使用symfony2,因此编写长查询不会成为一个问题,我主要担心的是上面的问题,这已经从一个表跳到了八个,而联系人只是我需要使用的一个区域像这样的模式。
答案 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)
);