这是这种数据库设计的正确方法

时间:2011-04-05 19:28:12

标签: php mysql

我有四张桌子,即

countries,states,cities,areas

这将是我数据库表的最佳可行解决方案

方法A:

CREATE TABLE IF NOT EXISTS `countries` (
`id` int(11) auto_increment NOT NULL,
`name` varchar(50) NOT NULL,
PRIMARY KEY  (`id`),
UNIQUE(`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `states` (
`id` int(11) auto_increment NOT NULL,
`name` varchar(50) NOT NULL,
`country_id` int(11) NOT NULL,
PRIMARY KEY  (`id`),
UNIQUE(`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `cities` (
`id` int(11) auto_increment NOT NULL,
`name` varchar(50) NOT NULL,
`state_id` int(11) NOT NULL,
PRIMARY KEY  (`id`),
UNIQUE(`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `areas` (
`id` int(11) auto_increment NOT NULL,
`name` varchar(50) NOT NULL,
`zipcode` int(11) NOT NULL,
`city_id` int(11) NOT NULL,
PRIMARY KEY  (`id`),
UNIQUE(`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

方法B:

CREATE TABLE IF NOT EXISTS `countries` (
`id` int(11) auto_increment NOT NULL,
`name` varchar(50) NOT NULL,
PRIMARY KEY  (`id`),
UNIQUE(`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `states` (
`id` int(11) auto_increment NOT NULL,
`name` varchar(50) NOT NULL,
`country_id` int(11) NOT NULL,
PRIMARY KEY  (`id`),
UNIQUE(`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `cities` (
`id` int(11) auto_increment NOT NULL,
`name` varchar(50) NOT NULL,
`state_id` int(11) NOT NULL,
`country_id` int(11) NOT NULL,
PRIMARY KEY  (`id`),
UNIQUE(`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `areas` (
`id` int(11) auto_increment NOT NULL,
`name` varchar(50) NOT NULL,
`zipcode` int(11) NOT NULL,
`city_id` int(11) NOT NULL,
`state_id` int(11) NOT NULL,
`country_id` int(11) NOT NULL,
PRIMARY KEY  (`id`),
UNIQUE(`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

谢谢..

7 个答案:

答案 0 :(得分:2)

第一种不太可能出现同步问题。

第二种将通过非规范化提供更好的性能。

可能的相关主题:What is a good way to denormalize a mysql database?

答案 1 :(得分:1)

如果输入不匹配的数据,第二个版本将导致严重的问题。获取以下示例数据:

countries: Canada, USA
states: Saskatchewan, Michigan
cities: Saskatoon, Detroit
zipcode: 90210 (california)

insert into  area (...) ('Canada', 'Michigan', 'Saskatoon', 90210)

所有单独有效,但整个记录完全错误。然而,按照你的设计,它应该是有效的。

答案 2 :(得分:0)

这可能取决于您将在这些表上运行哪些查询。通常,A是标准化的,而B不是(A将使用更少的空间)。

答案 3 :(得分:0)

我将从方法A开始,但如果结果表明性能需要链中的其他列,我只会根据需要添加它们。

请确保制作_id列索引。

答案 4 :(得分:0)

乍一看我更喜欢方法A,但是如果不知道你想要的关系和约束的具体细节,就不可能断然说一个人比另一个人“更好”。遵循您的应用程序的功能要求。

恭喜您寻求规范化的方法:很高兴看到它!

答案 5 :(得分:0)

我个人会选择第一个[方法A]。例如,如果您知道某个区域的城市ID,则会自动知道状态ID和国家/地区ID。虽然第二个可能会更方便,但如果说城市搬到了另一个州,你可能会遇到问题。

答案 6 :(得分:0)

最好从标准化表格开始。如果您的RDBMS自动管理缓存的列更新,我只会建议方法B.例如,如果您错误地将洛杉矶放置在密歇根州,则需要更新多个位置(除非您有触发器会更新非规范化表中的级联信息)。但是没有触发器,方法A毫无疑问是最好的形式。

当然,假设在查看方法A的定义时,您的约束与通用解释隐含的约束相匹配。