单个Big SQL Server查找表

时间:2015-01-06 14:59:12

标签: sql-server database sql-server-2008

我有一个带有雪花样式架构的SQL Server 2008数据库,因此有许多不同的查找表,如语言,国家,状态,状态等。所有这些查找表具有几乎相同的结构:两列,代码和解码。我的项目经理希望所有这些不同的表都是一个BIG表,所以我需要另一个列,比如CodeCategory,这个大表的主键列是CodeCategory和Code。问题是,对于任何具有实际代码的表(比如语言代码),我无法在这个大的解码表中建立外键关系,因为CodeCategory不在事实表中,只是代码。代码本身不是唯一的(它们将在CodeCategory中),因此我无法将FK从事实表代码字段转换为Big查找表代码字段。

所以我错过了什么,或者这是不可能做到的,仍然可以在相关的表格中做FK?我希望我能做到这一点:有一个FK,其中我在查找表中匹配的列之一将匹配字符串常量。像这样(我知道这是不可能的,但它让你知道我想做什么):

ALTER TABLE [dbo].[Users]  WITH CHECK ADD CONSTRAINT [FK_User_AppCodes] 
FOREIGN KEY('Language', [LanguageCode])
REFERENCES [dbo].[AppCodes] ([AppCodeCategory], [AppCode])

以上不起作用,但如果确实如此,我会得到我需要的FK。如果我有字符串'语言',在T-SQL中有什么方法可以替代代码中的表名吗?

我绝对需要FK这样,如果不可能这样,那么我将不得不坚持我可能的小查找表。任何帮助将不胜感激。

布赖恩

2 个答案:

答案 0 :(得分:4)

实现这一目标并非不可能,但是不可能完成这个在几个层面上不会损害系统。

虽然单个查找表(如已经指出的那样)是一个真正可怕的想法,但我会说这个模式不需要单个字段PK或者它是自动生成的。它需要一个由([AppCodeCategory], [AppCode])组成的复合PK,然后 BOTH 字段需要存在于事实表中,这两个字段的复合FK将返回PK。同样,这不是对这一特定目标的认可,只是技术说明,在其他更合适的情况下可以使用复合PK和FK。

这种常量方法的主要问题是每个常量都是它自己的事物:语言,国家,国家,Statii等都是完全独立的实体。虽然数据库中它们的结构是相同的(截至今天),但该结构中的数据并不代表相同的事物。您将被锁定在一个模型中,该模型要么不允许以后添加其他查找字段(例如语言和国家/地区的ISO代码,而不是其他的,或者与不适用于其他国家/地区相关的内容),或者需要添加NULLable字段无法知道他们应用了哪些类别(有趣的调试问题和/或向新人解释 - 他们已经在那里工作了2天并且负责撰写新报告 - 3数字ISO国家代码不适用于“已删除”状态。

此方法还要求您在所有相关表中维护任意“类别”字段。那就是每次查询。因此,如果您在事实表中有CountryCodeLanguageCodeStateCode,则每个FK都会获得匹配的CategoryID字段,因此现在这是6个字段而不是3.即使您能够使用TINYINT作为CategoryID,如果你的事实表甚至有2亿行,那么这三个额外的1字节字段现在需要600 MB,这会对性能产生负面影响。让我们不要忘记备份需要更长时间并占用更多空间,但磁盘便宜,对吧?哦,如果备份需要更长时间,那么恢复也需要更长的时间,对吧?哦,但桌子有接近10亿行?甚至更好; - )。

虽然这种方法看起来现在可能更“干净”或“更容易”,但从长远来看,实际上成本更高,特别是在浪费的开发人员时间方面,因为你(和/或其他人)在未来尝试解决与这种糟糕的设计选择相关的问题。

有没有人甚至问过你的项目经理这是什么意思?这是一个合理的问题,如果您要花费一些时间来对系统进行更改,那么花费的时间会有明显的好处。它当然不会使数据与数据交互变得更容易,事实上会使其变得更难,特别是如果您为“类别”而不是TINYINTSMALLINT选择字符串。

如果你的PM仍然按下这个更改,那么作为该项目的一部分,应该要求相应地更改应用程序代码中的任何enum,以便它们与数据库中的匹配。由于数据库的价值在一起,你可以在C#中实现这一点(假设您的应用程序代码在C#中,如果没有,则转换为适当的),方法是使用第一个模式明确设置enum值X位是“类别”,其余Y位是“值”。例如:

假设“国家”类别== 1和“语言”类别== 2,您可以这样做:

enum AppCodes
{
  // Countries
  United States  = 1000001,
  Canada         = 1000002,
  Somewhere Else = 1000003,

  // Languages
  EnglishUS = 2000001,
  EnglishUK = 2000002,
  French    = 2000003
};

荒诞?完全。但也类似于将所有查找表合并到单个表中的请求。什么对鹅有好处对雄鹅有好处,对吗?

答案 1 :(得分:0)

是否建议这样做,以便最大限度地减少CRUD操作对常设数据所需的管理屏幕数量?我之前一直在这里,并认为构建一个通用屏幕更好/更安全/更容易,该屏幕使用元数据来决定从哪个表中提取/写入。这需要更多的工作来构建,但保持数据库架构正确#39;。

所有常设数据表都具有相同的基本结构,它们主要用于下拉人群,偶尔还有其他字段用于业务规则。