使用联接优化sql查询
我有一个表,它存储了一个人近1000万行的信息 当前状态是person表上的char(2)字段。正如您所期望的那样,这会导致大量数据重复。如果我将状态数据规范化到它自己的表中,并在person表中为它创建一个FK,这会导致更快的查询时间吗 之前:使用联接优化sql查询,sql,sql-server,performance,tsql,join,Sql,Sql Server,Performance,Tsql,Join,我有一个表,它存储了一个人近1000万行的信息 当前状态是person表上的char(2)字段。正如您所期望的那样,这会导致大量数据重复。如果我将状态数据规范化到它自己的表中,并在person表中为它创建一个FK,这会导致更快的查询时间吗 之前: SELECT Name, City, State FROM Person WHERE State = 'WI' 之后: SELECT p.Name, p.City, s.Name as State FROM Person p INNER JO
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'
在我看来,这将提高性能,但在优化查询方面,我远不是专家。规范化可能导致性能下降,但在这种情况下,它几乎不会提高性能,因为现在服务器必须查看磁盘上的两个位置,而不是一个位置 标准化有两个目的:
如果您只讨论2个字符,那么将其拆分到新表中可能没有多大用处
(但是,考虑有一个特定的值域)-如果某人进入VX或其他不允许的值,当没有非正规化时,没有适当的或有效的约束方式
如果你在谈论其他信息,比如美国邮政缩写(2个字符)和州全名,也许还有其他一些信息,那么绝对是的——把它分开作为实践的一个问题,你应该总是在适当的规范化方面犯错——然后经过长时间的争论,你才应该考虑反义化。 < P>如果你在状态表上创建一个非常窄的键,比如TINYINT,那么你可以提高性能,但不能保证。不过,这完全值得测试 考虑对每个表进行复制,对它们进行适当的索引,然后使用分析器同时对这两个表运行查询 你最终可能会获得1%的速度提升
尽管如此,规范化很少是个坏主意…在字符串索引上搜索(理论上)比在int索引上搜索慢得多。这意味着是的;规范化数据将使其更快。在实践中,我经常看到这种差异是最小的;YMMV。您可能需要预缓存或单独选择状态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');
与查询一样,最好进行测试和优化。要节省的空间不多。
您可以使用字节(tinyint)作为状态表上的主键,因为只有50个状态。
字符(2)是两个字节。
因此,在person表中,每行只保存一个字节 压缩数据的优点是磁盘空间和内存更少。
对于固定数量的内存,如果数据较小,则内存中存储数据的可能性较高 我认为1字节的大小差异不值得连接的开销 但我会正常化,因为这是一种良好的做法。
为什么让某人进入JZ状态 第三范式失败
如果存在重复组,请将这些组划分为它们自己的关系 您可以使用char(2)作为状态表中的主键,以便char(2)与char(2)直接匹配。
这将满足第三范式,因为值限制在50个状态。
在这种情况下,您不需要加入select,因为实际值在主表中。
在插入或更新时,FK关系是强制的,因此它必须是有效状态
如果您想报告整个州,您可以在州表中添加一列全名。好的。。在您的查询中,您正在做一些非最佳的事情
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'的状态下创建一个筛选索引
这会有一些帮助。为你的
状态
列编制索引可能会比FK
更好。因为状态列只是一个CHAR(2)
,你似乎没有其他与状态相关的数据(例如人口),我们预计状态两个字符的代码不会很快改变,我甚至不想考虑单独的状态表“标准化”。如果你想正常化,考虑用一个单独的<代码> >锡蒂>代码>表,其中的代码为<代码>名称>代码>和<代码>状态> /代码> @ BLAM,我认为“VA”或“NC”是一个有效的键值,在这种情况下,我认为任意决定某个数字键计算一个素数键是任意的,但是一个字符(2)(它永远不会改变)不是。我认为使用CHAR(2)
的重复值不会比使用数字外键的重复值多。@bum只是为了澄清一下,理论上我们可以添加一个State
表,其中包含字段code
,name
,population
,area
,etc,其中code
是CHAR(2)
类型的主键,使用“VA”和“NC”等值。但在这种情况下,似乎没有与状态相关的附加信息,因此实际上不需要状态
表,因为它只有代码
,没有附加字段。我倾向于将其设计为具有状态值的查找表,您可以使用该表确保只输入有效的状态,但我会将这两个字符与地址的其余部分一起存储。这是一个过于笼统的说法,不可能是正确的。你可以详细说明和解释为什么在这种情况下可能是这样,但那远远不是真的。谢谢。我会的