我正在创建一些用于存储日志条目的数据库表。在正常情况下,我总是会规范化并且永远不会把价值放在一起,但我并不是100%确信这是一个好主意。
我可以正常化并拥有:
LogEntry与LogCategory有多对多的关系,LogEntry与LogEntryProperty(名称/值对)有1对多的关系。
Alternative是一个非规范化版本,它只有LogEntry,类别存储为逗号分隔的字符串类别列表,属性存储为Name:Value格式化属性的逗号限制列表。听起来很丑陋,从报告,性能和可搜索性的角度来看,我不确定这是不是更好。
哪个更好?
感谢。
答案 0 :(得分:6)
因为只有几个不同的属性,所以我会远离名称 - 值对,并为每个属性提供一个单独的表,其中包含正确的名称和数据类型 。我使用了通用Property_
,仅用于演示。
这里的事情是确保在缺少属性表时不将值插入属性表中,换句话说,所有属性值都不是NULL。
为了让生活更轻松,请定义视图
create view dbo.vLogs AS
select
LogCategoryName
, LogTime
, p1_Value
, p2_Value
, p3_Value
, p4_Value
, p5_Value
from LogEntry as e
left join Property_1 as p1 on p1.LogEntryId = e.LogEntryId
left join Property_2 as p2 on p2.LogEntryId = e.LogEntryId
left join Property_3 as p3 on p3.LogEntryId = e.LogEntryId
left join Property_4 as p4 on p4.LogEntryId = e.LogEntryId
left join Property_5 as p5 on p5.LogEntryId = e.LogEntryId
left join LogEntryCategory as x on x.LogEntryId = e.LogEntryId
left join LogCategory as c on c.LogCategoryID = x.LogCategoryID
这个观点(查询)看起来复杂而漫长;但是,如果您尝试下面的查询并查看执行计划,您可能会注意到选择列表中未提及的属性表未包含在计划中(未触及)。
select
LogCategoryName
, LogTime
, p1_Value
, p2_Value
from dbo.vLogs
where LogCategoryName = 'some_category'
and LogTime between from_time and to_time
如果你需要像这样简单的东西
select max(p1_Value)
from dbo.vLogs
where LogTime between '2011-07-18' and '2011-07-19'
这是执行计划,因为您只能看到涉及两个表。
这称为表(连接)消除,你需要SQL Server,Oracle,PostgreSql 9.x,...为此工作 - 将无法在MySql(尚未)上工作。
每次添加属性时,都必须添加新表并修改视图。
答案 1 :(得分:1)
我建议正确规范化。