我有一张桌子,可存储近千万行的人的信息。
目前State是person表上的char(2)字段。这会导致大量重复数据,如您所料。如果我将状态数据规范化为它自己的表并在人员表中为它创建一个FK,这会导致更快的查询时间吗?
在:
SELECT Name, City, State FROM Person WHERE State = 'WI'
后:
SELECT p.Name, p.City, s.Name as State
FROM Person p
INNER JOIN State s ON p.State == s.Id
WHERE s.Name = 'WI'
在我看来,这会提高性能,但在优化查询方面,我远非专家。
答案 0 :(得分:2)
规范化可以导致降低性能,但在这种情况下很少会提高你的性能,因为现在服务器必须查看两个地方磁盘而不是一个。
规范化有两个目的:
您的查询不会受益于
这些优势答案 1 :(得分:1)
如果你只谈论2个字符 - 那么将它拆分成新表可能没用多少。
(但是 - 考虑到允许的特定值域 - 如果有人输入VX或其他一些非允许的值 - 在非规范化时无法正确或有效地约束)
如果你正在谈论其他信息,比如美国邮政abbraviation(2个字符)和州名,可能还有其他一些信息,那么绝对是 - 将它拆开。
作为一种惯例,你应该总是在正确的规范化方面犯错(imo) - 然后在经过冗长的论证之后才应该考虑非规范化。
答案 2 :(得分:1)
如果在状态表上创建一个非常窄的键,如TINYINT,那么 可以提高性能,但不能保证。但这完全值得测试。
考虑制作每个表的副本,正确索引它们,然后使用分析器同时在两个表上运行查询。
最终速度可能会提高1%。
尽管如此,正常化很少是一个坏主意......
答案 3 :(得分:0)
没有太多空间可以保存 您可以在状态表上使用byte(tinyint)作为主键,因为只有50个状态 Char(2)是两个字节 因此,您只需在人员表中每行保存一个字节。
压缩数据的优点是磁盘空间更少,内存也更少 对于固定数量的内存,如果数据较小,则内存中数据的可能性更高。
我不认为1字节的大小差异值得加入的开销。
但我会因为这是一个好习惯而正常化 为什么要让某人进入JZ州?
第三次正常表格失败
Achieve 3NF
如果有重复的组,请将组分为各自的关系。
您可以在状态表中使用char(2)作为PK,因此char(2)与char(2)直接匹配。
这将满足第3范式,因为这些值仅限于50个州
在这种情况下,您不需要加入select,因为实际值在主表中
在插入或更新时,强制执行FK关系,因此它必须是有效状态。
如果您想报告整个州,可以在状态表中添加一个列作为全名。
答案 4 :(得分:0)
嗯..在您的查询中,您正在做一些非最佳的事情。
SELECT p.Name, p.City, s.Name as State
FROM Person p
INNER JOIN State s ON p.State == s.Id
WHERE s.Name = 'WI'
您获得所有状态记录的人员详细信息,之后您使用“WI”过滤状态。
如果你试试这个,你的状态就会减少!
SELECT p.Name, p.City, s.Name as State
FROM Person p
INNER JOIN State s
ON p.State == s.Id
and s.Name = 'WI'
为什么呢?因为您只会获取名称为WI而不是所有州列的州列。
之后..如果它适合您的索引,请在name ='WI'的状态下创建一个过滤索引
这会有所帮助..
答案 5 :(得分:-2)
搜索字符串索引(理论上)比搜索int索引要慢得多。这意味着是;规范化您的数据会使其更快。在实践中,我经常看到差异微乎其微;因人而异。您可能必须预先缓存或单独选择状态ID:
SELECT p.Name, p.City, s.Name as State
FROM Person p
INNER JOIN State s ON p.State == s.Id
WHERE s.Id = (select id from State where State.Name = 'WI');
与查询一样,最好进行测试和优化。