在我们的库存数据库(SQL Server 2008标准版)中,我们有一个表(称为股票结果),用于按库存期存储每个库存商品的结果,看起来像这样:
<< StockResults >>
PK StockPeriodID int
PK StockItemID int
OStockCost money
OStockQty real
DeliveriesQty real
CreditsQty real
TransfersInQty real
TransfersOutQty real
CStockQty real
OStockAmt money
DeliveriesAmt money
CreditsAmt money
TransfersInAmt money
TransfersOutAmt money
CStockAmt money
... except that it has about 40 columns
我们正在考虑规范化该表,以便我们有一个用于字段的表和另一个用于数据的表。像这样:
create table StockResults_Fields
(FieldID int, FieldName varchar(20), FieldDataType varchar(10))
create table StockResults_Values
(StockPeriodID int, StockItemID int, FieldID int, FieldName varchar(20), FieldDataType varchar(10))
我们考虑这样做的原因是为了提高表的性能并防止死锁(我们目前正在获得)。关于规范化以减少死锁的建议来自本文:Reducing SQL Server Deadlocks。
我担心的是结果表(已经很大)会变得更大。并且大多数报告在与当前结构类似的结构中显示数据 - 新方法将具有相当多的连接。
在我们开始涉及大量工作的事情之前,在我们开始之前,是否有人对结果的标准化结构和性能优势有任何建议?
编辑:感谢您的建议。我有一种直觉,认为2桌的方法不是可行的方法,但我不确定为什么 - 直到现在。锁定错误已经解决:我们有一个没有聚簇索引的表,但快照隔离看起来像我们可能会考虑的那样。
答案 0 :(得分:7)
听起来您在设计系统时知道所有需要的列。如果是这种情况,您应该绝对不继续您提出的设计。
这种设计的唯一可能原因是,如果您不了解设计时需要的所有字段,并且需要在生产后添加一些字段。
我预测你的双桌方法会比现在的方法表现得更差。
此外,这与规范化无关,至少根据我的定义。你要做的是从关系模型转向元数据模型。
(编辑:您还应发布有关死锁发生的时间/地点的更多信息,如果这是您要解决的问题的根源)。
答案 1 :(得分:2)
您可以先尝试将数据库更改为Snapshot Isolation级别,以查看这是否会减少争用\锁定。我最近为MS Dynamics安装(包含许多列的大型表)做了这个,并且它已经得到了很好的待遇(是的,我首先得到了Microsoft的确定!)。如果它有效,它将比您的表格重构提案快得多。
答案 2 :(得分:1)
我猜你会遇到死锁的原因之一就是你试图在表中做太多而且需要规范化的子表,而不是你建议的那样(这不是规范化数据的任何一段想象力)(请阅读http://www.simple-talk.com/opinion/opinion-pieces/bad-carma/,了解您的建议是个坏主意的原因)。
在我看来,您的表结构不断更新,因为它总结了数据。将对数据的更改放入单独的行中,然后汇总到仅定期更新的报表或数据仓库中。甚至可以在视图中执行摘要。但是不通过视图对表进行数据更改。
因此,我会有一个库存表来定义库存的分号和描述性详细信息,然后为每种类型的数据定义一个可能随时间变化的子表。
因此,stock_transaction表将以库存ID和商品数量开头 如果你得到一个新的股票,它会添加一个记录与收到的总数。然后,如果您发出一个项目,它将在项目数量等中添加一个带有-1的记录。然后,要查找项目总数,您需要对数据求和。要查找已发放的库存项目总数,您可以将负值相加并取绝对值。这就是我工作的大多数仓库库存应用程序的方式。此外,您还有其他字段,以便您可以跟踪股票的去向和交易日期,以便您可以在详细级别查看整体情况。
现在没有更好地了解整个表格以及文件的含义以及填充方式,我无法建议可能需要创建哪些子表。但是,如果将数据分成自然的子记录,那么你应该减少死亡数量并对系统中发生的事情进行定义。试想一下,如果数据需要经常更新,那么该字段就是子表的候选者。您可以将子表中的几个当前字段组合在一起,这取决于信息的相关程度。
但是,像这样的重组是一项重大工作,需要花费很多时间才能完成并迁移和测试数据和应用程序的变化。如果您现在可以通过分区或使用快照隔离来获得更好的性能,就像其他人所建议的那样,那将是一种可行的方式。如果你获得了更好的性能,但它不够好,那么重新设计,但是现在使用其他技术来提高性能,而你花费一年左右的时间来重新签名。我只提出这个建议,以防你不能以任何其他方式解决性能问题,以显示你真正规范化数据的样子,并让你知道遵循这条路径会有多贵。
答案 3 :(得分:0)
你可能能够解决这里的死锁问题,但是为了提高性能,你是否尝试将表分区为单独的spindels? 您也可以像redsquare所说的那样更改快照隔离级别,或者如果您不希望所有查询具有相同的隔离级别,则可以向SELECT查询添加WITH(NOLOCK)