Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用联接优化sql查询_Sql_Sql Server_Performance_Tsql_Join - Fatal编程技术网

使用联接优化sql查询

使用联接优化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

我有一个表,它存储了一个人近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 JOIN State s ON p.State == s.Id
WHERE s.Name = 'WI'

在我看来,这将提高性能,但在优化查询方面,我远不是专家。

规范化可能导致性能下降,但在这种情况下,它几乎不会提高性能,因为现在服务器必须查看磁盘上的两个位置,而不是一个位置

标准化有两个目的:

  • 减少磁盘上存储的数据量
  • 允许在单个位置更新数据
  • 您的查询将不会从以下任何一个优点中受益:

  • char(2)和int(外键)之间没有太大区别
  • 状态的两位数代码永远不会更改,因此您永远不需要更新它

  • 如果您只讨论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”等值。但在这种情况下,似乎没有与状态相关的附加信息,因此实际上不需要
    状态
    表,因为它只有
    代码
    ,没有附加字段。我倾向于将其设计为具有状态值的查找表,您可以使用该表确保只输入有效的状态,但我会将这两个字符与地址的其余部分一起存储。这是一个过于笼统的说法,不可能是正确的。你可以详细说明和解释为什么在这种情况下可能是这样,但那远远不是真的。谢谢。我会的