SQL数据库设计最佳实践(地址)

SQL数据库设计最佳实践(地址),sql,database-design,Sql,Database Design,当然,我意识到没有一种“正确的方法”来设计SQL数据库,但我想了解一下在我的特定场景中,什么是好的,什么是坏的 目前,我正在设计一个订单输入模块(带有SQL Server 2008的Windows.NET 4.0应用程序),当涉及可应用于多个地点的数据时,我在两个设计决策之间左右为难。在这个问题上,我将特别提到地址 地址可以由各种对象(订单、客户、员工、装运等)使用,并且它们几乎总是包含相同的数据(地址1/2/3、城市、州、邮政编码、国家等)。我最初打算将这些字段作为列包含在每个相关表中(例如,

当然,我意识到没有一种“正确的方法”来设计SQL数据库,但我想了解一下在我的特定场景中,什么是好的,什么是坏的

目前,我正在设计一个订单输入模块(带有SQL Server 2008的Windows.NET 4.0应用程序),当涉及可应用于多个地点的数据时,我在两个设计决策之间左右为难。在这个问题上,我将特别提到地址

地址可以由各种对象(订单、客户、员工、装运等)使用,并且它们几乎总是包含相同的数据(地址1/2/3、城市、州、邮政编码、国家等)。我最初打算将这些字段作为列包含在每个相关表中(例如,订单将包含地址1/2/3、城市、州等,客户也将包含相同的列布局)。但我的一部分人希望将干式/规范化原则应用于此场景,即在适当的表中有一个名为“Addresses”的表,该表通过外键引用

CREATE TABLE DB.dbo.Addresses
    (
        Id          INT
                    NOT NULL
                    IDENTITY(1, 1)
                    PRIMARY KEY
                    CHECK (Id > 0),

        Address1    VARCHAR(120)
                                NOT NULL,

        Address2    VARCHAR(120),

        Address3    VARCHAR(120),

        City        VARCHAR(100)
                    NOT NULL,

        State       CHAR(2)
                    NOT NULL,

        Country     CHAR(2)
                    NOT NULL,

        PostalCode  VARCHAR(16)
                    NOT NULL
    )

CREATE TABLE DB.dbo.Orders
    (
        Id          INT
                    NOT NULL
                    IDENTITY(1000, 1)
                    PRIMARY KEY
                    CHECK (Id > 1000),

        Address     INT
                    CONSTRAINT fk_Orders_Address
                    FOREIGN KEY REFERENCES Addresses(Id)
                    CHECK (Address > 0)
                    NOT NULL,

        -- other columns....
    )

CREATE TABLE DB.dbo.Customers
    (
        Id          INT
                    NOT NULL
                    IDENTITY(1000, 1)
                    PRIMARY KEY
                    CHECK (Id > 1000),

        Address     INT
                    CONSTRAINT fk_Customers_Address
                    FOREIGN KEY REFERENCES Addresses(Id)
                    CHECK (Address > 0)
                    NOT NULL,

        -- other columns....
    )
从设计的角度来看,我喜欢这种方法,因为它创建了一种易于更改的标准地址格式,也就是说,如果我需要添加地址4,我只需将其添加到一个位置,而不是每个表中。然而,我可以看到,构建查询所需的连接数量可能有点疯狂


我想我只是想知道,是否有任何企业级SQL架构师成功地使用过这种方法,或者这种方法所创建的连接数是否会产生性能问题?

您通常会尽可能地规范化数据,因此请使用“地址”表

您可以在使用索引之后使用视图对数据进行非标准化处理,并应提供一种方法来访问具有简单引用的数据,同时使底层结构完全标准化


联接的数量不应该是一个主要问题,基于索引的联接不会造成太大的开销。

将地址分解到它自己的表中,这样做是正确的。我想补充几点建议

  • 考虑从Customers/Orders表中删除Address FK列,并改为创建连接表。换句话说,在您的设计中,现在将客户/地址和订单/地址视为多对多关系,以便将来可以轻松支持多个地址。是的,这意味着引入更多的表和联接,但是您所获得的灵活性是值得付出努力的

  • 考虑为城市、州和国家实体创建查找表。地址表的城市/州/国家列则由指向这些查找表的FK组成。这使您能够保证所有地址的拼写一致,并在将来需要时为您提供存储额外元数据(例如城市人口)的位置


  • 有一个分开的地址表是可以的


    但是,您必须避免这样的诱惑,即允许多行引用同一地址,而不使用适当的系统来管理选项,以便用户决定更改地址是否以及如何将一行拆分为新地址更改,即您具有相同的计费地址和收货地址。然后一个用户说他们的地址正在改变。首先,旧订单可能(应该?)需要保留发货地址,所以您不能就地更改。但是用户可能还需要说,我正在更改的地址只会将发货地址更改为。

    只有当地址本身是实体时,您才会希望地址位于单独的表中。实体具有标识(这意味着两个对象是否指向相同的地址或不同的地址很重要),并且它们有自己的生命周期,不同于其他实体。如果你的域名是这样的话,我想这是很明显的,你不需要问这个问题

    解释地址的易变性,例如发货地址是订单的一部分,不能从它所属的订单下更改。这表明配送地址没有自己的生命周期。把它当作一个单独的实体来处理,只会导致更多的出错机会

    “规范化”特别是指从数据中删除冗余,这样就不会在不同的位置表示相同的项。这里唯一的冗余在DDL中,它不在数据中,因此“规范化”在这里不相关。(JPA有嵌入式类的概念,可以解决冗余问题)


    TLDR:如果地址确实是一个实体,具有自己独特的标识和生命周期,请使用单独的表。否则不要这样做。

    你必须自己回答的问题是,日常语言中的同一地址实际上是否与数据库中的地址相同。如果有人“更改了地址”(口语),他实际上会将自己链接到另一个地址。地址本身只有在街道更名、邮政编码改革或核武器袭击时才会改变。而这些都是罕见的事件(希望在大多数情况下)。这就是您的主要利润:在一个地方更改多行(多个表)

    如果您实际上应该更改模型中的地址(即表地址上的
    更新
    ),那么对于链接到它的其他行,这可能有效,也可能无效。而且,根据我的经验,即使是完全相同的地址,出于不同的目的也必须看起来不同。理解语义上的差异,你就会找到最能代表真实世界的正确模型

    我有许多数据库,其中我使用了一个通用的街道表(它使用了一个城市表(它使用了一个国家表…)。结合街道编号,可以将其视为地理编码(lat/lon),而不是“街道名称”。不同表(或行)之间不共享地址。更改街道名称和邮政编码casca
    insert into Addresses 
      (Address1, Address2, Address3, City, State, Country, PostalCode)
    values
      ('President Obama', '1600 Pennsylvania Avenue NW', NULL, 'Washington', 'DC', 'US', '20500'),
      ('President Obama', '1600 Pennsylvania Avenue NW', NULL, 'Washington', 'DC', 'US', '20500'),
      ('President Obama', '1600 Pennsylvania Avenue NW', NULL, 'Washington', 'DC', 'US', '20500'),
      ('President Obama', '1600 Pennsylvania Avenue NW', NULL, 'Washington', 'DC', 'US', '20500');
    
    select * from Addresses;
    
    1;President Obama;1600 Pennsylvania Avenue NW;;Washington;DC;US;20500
    2;President Obama;1600 Pennsylvania Avenue NW;;Washington;DC;US;20500
    3;President Obama;1600 Pennsylvania Avenue NW;;Washington;DC;US;20500
    4;President Obama;1600 Pennsylvania Avenue NW;;Washington;DC;US;20500
    
    Address: {
        CityId
        // With other fields
    }
    
    City: {
       CityId
       StateId
      // Other fields
    }
    
    State: {
       StateId
       CountryId
     // Other fields
    }
    
    Country: {
      CountryId
      // Other fields
    }