【发布时间】:2012-06-01 19:20:41
【问题描述】:
我今天就我的应用程序中的数据库设计和性能问题提出了以下问题。
DB Design and Data Retrieval from a heavy table
但是,没有得到太多的回复。我不知道,我可能没有正确解释这个问题。现在,我重新定义了我的问题,希望得到专家的一些建议。
我在从特定表中选择数据时遇到性能问题。应用的业务逻辑如下: 我有许多导入过程,这些过程会导致在其父列名称下创建数据透视列,同时将它们显示给用户。随着列的旋转,系统需要时间将行转换为列,这会导致性能下降。 与此功能相关的数据库表如下: 可以有 N 个客户端。 CLT_Clients 表存储客户信息。
一个客户可以有 N 个项目。 PRJ_Projects 表存储项目信息和到客户端的链接。
一个项目可以有 N 个列表。 PRJ_Listings 表存储列表信息和项目链接。
可以有 N 个与列表关联的源实体。 ST_Entities 表存储源实体信息和列表链接。
此源实体是包含 InvestorID、头寸值、源日期、活动和公式状态的实际导入。
The name of the import e.g. L1Entity1 is stored in ST_Entities table alongwith ID field i.e. EntityID
InvestorID, Position, Source Date, Active and Formula values get stored in ST_Positions table
数据库图
数据需要如下查看:
通过这种设计,我能够处理 N 次导入,因为 Position、Source Date、IsActive、Formula 列会被透视。
我在此设计中面临的问题是,当系统必须为超过 10-12 个源实体选择数据时,系统执行速度非常慢,并且要求显示大约 150 个源实体。因为数据不是按行存储的,我需要按列显示,因此编写动态查询来旋转这些需要很长时间的列。
问题 1: 请对我当前的数据库设计提出评论/建议,如果它是正确的,或者需要根据新设计进行更改,请为 Position、Source Date、IsActive、Formula 各取 150 列;以这种新方式,数据已经以我需要检索的方式存储,即我不必旋转/取消旋转它。但缺点是:
a) 此表中的列将超过 600 列?
b) 源实体将有限制,即 150 个。
问题 2:如果我需要坚持目前的状态,可以做些什么来提高性能?
请参阅下面的索引和枢轴方法信息:
关于 Position 表中的索引,我也采用了带有聚集索引的 ProjectID 字段,因为数据是根据 ProjectID 或 EntityID 从 Position 表中选择的。
当EntityID 用于从Position 表中选择数据时,它总是在JOIN 中使用。并且每当使用 ProjectID 从该表中选择数据时,它总是在 WHERE 中使用。
这里要注意的是,我在 ProjectID 上有一个聚集索引,但我没有在 Pivoted 列或 EntityID 上获取任何索引。这里有什么改进的余地吗?
使用的旋转方法:
Example 1:
'Select * From
(
Select DD.InvestorID,Cast(1 As Bit) As IsDSInvestor,DD.Position,
Case DD.ProjectID
When ' + CAST(@ProjectID AS VARCHAR) +' Then DE.SourceName
Else ''' + @PPDeliveryDate + '''+DE.SourceName
End As SourceName
From DE_PositionData DD
Inner Join DE_DataEntities DE ON DE.EntityID=DD.EntityID
Where DD.ProjectID IN (' + CAST(@ProjectID AS VARCHAR) +',' + CAST(@PreviousProjectID AS VARCHAR) +') AND InvestorID IS NOT NULL
) IDD
Pivot
(
max(Position) for SourceName in ('+ @DataColumns+')
) as p1'
示例2:
'Select * From
(
Select DD.InvestorID As DSSOFID,Cast(1 As Bit) As IsActiveInvestor,
Case ST.SourceTypeCode
When ''RSH'' Then Cast(IsNull(DD.IsActive,0) As Int)
Else Cast(IsNull(DD.IsActive,1) As Int)
End As IsActive,
''~''+DE.SourceName As ActiveSourceName
From DE_DataEntities DE
Left Join DE_PositionData DD ON DE.EntityID=DD.EntityID
Left Join
(
Select * From #DataSources
Where ProjectID=' + CAST(@ProjectID AS VARCHAR) +'
) ST ON ST.ESourceID=DE.ESourceID
Where DE.ProjectID=' + CAST(@ProjectID AS VARCHAR) +' AND ST.SourceTypeCode NOT IN (''PBC'',''EBL'',''REG'')
AND InvestorID IS NOT NULL
) IDD
Pivot
(
Max(IsActive) for ActiveSourceName in ('+ @DataColumns+')
) As p1'
【问题讨论】:
-
我认为您当前的 OLTP 架构没有问题。它似乎最适合您的追求。我认为你的报告布局是有问题的。你用什么来显示你的数据? Excel、SSRS、Web 表单等。无论哪种方式,我认为报告中的 600 列数据对于任何人来说都太多了。如果您可以详细说明您的报告媒介,或许可以建议更好的报告结构。您可能还想研究仓储数据和使用 SSAS。
-
Gareth,感谢您的快速回复。数据只需要在 Winform 中的网格中显示,用户可以在其中进行更改。这个 600 的数字是最坏的情况;网格中一般会有大约 150-200 列。
-
如果在 Winforms 上完成,最好的解决方案是不具有分层表单结构,因此用户可以选择一个客户端,通过单击一个项目来查看项目,他们可以然后编辑项目详细信息并查看所有相关列表。通过单击列表,他们可以编辑列表并查看所有位置?我想这是个人喜好,但我更愿意开发这种结构,并更喜欢它作为用户。您还可以按需检索数据,并随时减少从数据库检索的数据量。
-
抱歉 GarethD,我无法关注你。你同意我提出的数据库设计还是你有不同的想法?如果不同,请详细说明?
-
总而言之,我同意您的数据库设计,但我认为在具有 100 列的表单上显示数据是个坏主意。你有关系数据,所以你应该这样显示它。也就是说,您可能不需要在一个表单上显示每一位数据,从顶层开始,然后从那里扩展。因此,一个显示所有客户的表单,一个显示客户详细信息和所有项目的客户表单,然后另一个显示一个项目和所有列表等的表单。
标签: sql-server-2008 database-design query-optimization database-performance