我正在开发一个批处理应用程序,允许用户提交有关特定车辆信息的请求。用户可以使用VIN或车牌/状态组合提交请求。我提出了以下表结构:
VehiclesToBeProcessed
vehicle_id(fk)|user_id(fk)|status|start_time
车辆
vehicle_id|VIN|plate|state
vehicle_id(fk)|user_id(fk)|status|start_time
车辆
vehicle_id(pk)|field|value
车辆中的条目要么包含vin的一行:
1|"vin"|"123
或两个板/状态行:
2|"plate"|"abc 123"
2|"state"|"NY"
我认为第一个解决方案更容易查询而不会有任何明显的缺点。应该首选哪种设计?保证空字段真的是糟糕设计的指标吗?
答案 0 :(得分:2)
您的同事提出的是关于数据库设计的最终反模式。
Google为Bill Karwin的“反模式”一书和“EAV”。
询问你的同事他是如何强制执行“盘子”和“状态”值总是成对出现在他的数据库中。如果他指向应用程序代码,请询问他如何强制执行数据库只能通过他的应用程序更新。
你的解决方案比他好一千倍。仍然“更好”(从涉及避免所有空值的关系纯度的角度来看)是给每种类型的请求自己的表:
VehicleQueriesByVIN
USER_ID(FK)|状态| START_TIME | VIN
VehicleQueriesByPlate
USER_ID(FK)|状态| START_TIME |板|状态
如果要为每个查询保留历史跟踪状态,那么这些东西必须在自己的表中单独列出。
答案 1 :(得分:0)
总之:不。这是一个错位的优化案例。由于存储字符串,他的模式实际上平均会占用更多空间;当然,更复杂的代码和查询会有更糟糕的表现。
答案 2 :(得分:0)
将其视为识别车辆的多种方式。您的车辆有一个或多个身份。当地警察可以使用LPN识别您的车辆,而停车管理局可能使用许可证或主动/被动转发器,此外dmv可能依赖于vrn号码。
如果您真的想构建一种灵活的方式将车辆绑定到多个身份,我会使用身份类型表,这样车辆就可以拥有一个或多个身份。
<强> VehicleIdentity 强>
VehicleIdentity PK
VehicleID FK
IdentityValue
IdentityType(类型)
STATEID?
<强>车辆强>
VehicelID PK
我通过删除一个我认为没用的表来更新答案:)
答案 3 :(得分:0)
空无一物。它们对单表继承特别有用,如果你的系统需要&#34; Draft&#34;实体。
如果您使用像Postgres这样的质量数据库,则对空值没有存储惩罚。
无论如何,如果问题是&#34;我们需要A或B,A和B非常相似&#34;然后答案几乎总是表继承。如果要快速移动,请使用单表继承。如果NULL会让你感到难过,那就使用Class Table Inheritance。
--STI:
create table vehicle_identifiers (
id int primary key,
type text not null check (type in ( 'VIN', 'STATE_N_PLATE' ) )
vin null,
state char(2) null,
plate text null,
check ( ( type='VIN' and vin is not null ) or ( type='STATE_N_PLATE' and state is not null and plate is not null ) )
);
--CTI:
create table vehicle_identifiers (
id int primary key
);
create table vehicle_identifiers_vin (
id int primary key references vehicle_identifiers(id),
vin text not null
);
create table vehicle_identifiers_state_n_plate (
id int primary key references vehicle_identifiers(id),
state text not null,
plate text not null
);