但是,为了对通用存储库进行简单设计,所有涉及的表必须定义一个唯一的整数(C#中的Int32,sql中的int).到目前为止,这一直是桌子的PK和IDENTITY.
外键使用频繁,它们引用这些整数列.它们是一致性和ORM生成导航属性所必需的.
应用程序层通常执行以下操作:
>从表(*) – SELECT * FROM表加载初始数据
>更新 – UPDATE表SET Col1 = Val1 WHERE Id = IdVal
>删除 – DELETE FROM表WHERE Id = IdVal
>插入 – INSERT INTO表(cols)VALUES(…)
运营频率较低:
>批量插入 – BULK INSERT …进入表后跟(*)所有数据加载(以检索生成的标识符)
>批量删除 – 这是一个正常的删除操作,但从ORM的角度来看是“笨重的”:DELETE FROM表其中OtherThanIdCol = SomeValue
>批量更新 – 这是一个正常的更新操作,但从ORM的角度来看“庞大”:UPDATE表SET SomeCol = SomeVal WHERE OtherThanIdCol = OtherValue
*所有小表都在应用程序级别缓存,几乎所有SELECT都不会到达数据库.典型的模式是初始加载和许多INSERT,UPDATE和DELETE.
根据当前的应用程序使用情况,在任何表中达到100M记录的可能性非常小.
问题:从DBA的角度来看,有这个表设计限制我可能遇到的重大问题吗?
[编辑]
在阅读了答案(感谢很好的反馈)和参考文章后,我觉得我必须添加更多细节:
>当前的应用程序细节 – 我没有提到当前的Web应用程序,因为我想了解该模型是否可以重用于其他应用程序.但是,我的特殊情况是一个从DWH中提取大量元数据的应用程序.源数据非常混乱(以一种奇怪的方式非规范化,有一些不一致,在许多情况下没有自然标识符等),我的应用程序正在生成清晰的分离实体.此外,显示许多生成的标识符(IDENTITY),以便用户可以将它们用作业务键.除了大规模的代码重构之外,这还排除了GUID的使用.
>“他们不应该是唯一识别行的唯一方法”(Aaron Bertrand♦) – 这是一个非常好的建议.我的所有表都定义了一个UNIQUE CONSTRAINT,以确保不允许重复业务.
>前端应用驱动设计与数据库驱动设计 – 设计选择是由这些因素引起的
>实体框架限制 – 允许多列PK,但是their values cannot be updated
>自定义限制 – 具有单个整数键可以极大地简化数据结构和非sql代码.例如:所有值列表都有一个整数键和一个显示值.更重要的是,它保证标记为缓存的任何表都能够放入Unique int键 – >价值图.
>复杂的选择查询 – 这几乎不会发生,因为所有小的(<20-30K记录)表数据都在应用程序级别进行缓存.这使得编写应用程序代码时生活变得更加困难(更难编写LINQ),但数据库受到更好的打击:
>列表视图 – 在加载时不会生成SELECT查询(所有内容都被缓存)或查询如下所示:
SELECT allcolumns FROM BigTable WHERE filter1 IN (val1,val2) AND filter2 IN (val11,val12)
所有其他必需值都是通过缓存查找(O(1))获取的,因此不会生成复杂的查询.
>编辑视图 – 将生成如下所示的SELECT语句:
SELECT allcolumns FROM BigTable WHERE PKId = value1
(所有过滤器和值都是整数)
解决方法
> Bad habits to kick : putting an IDENTITY column on every table
但代理键确实具有有效的用例 – 请注意不要假设它们保证唯一性(有时为什么它们会被添加 – 它们不应该是唯一标识行的唯一方法).如果您需要使用ORM框架,并且您的ORM框架需要单列整数键,即使在您的真实密钥不是整数,也不是单个列或两者都不是的情况下,请确保定义唯一约束/索引对于你真正的钥匙.