【问题标题】:Problematic database design causing performance issues有问题的数据库设计导致性能问题
【发布时间】:2017-07-22 11:39:55
【问题描述】:

我正在设计一个基于 C#/SQL Server 的多模块应用程序。我的设计是将所有通用查找值保存在一个名为KeyTypeValues 的表中。此表与KeyTypes 相关,它定义了它是什么类型的数据。

例如:

oms.KeyTypes
------------
Id          INT NOT NULL IDENTITY(1,1) PRIMARY KEY
KeyTypeName VARCHAR(40) NOT NULL
...

oms.KeyTypeValues
-----------------
Id                  INT NOT NULL IDENTITY(1,1) PRIMARY KEY
KeyTypeId           INT NOT NULL (FOREIGN KEY to oms.KeyTypes Id)
KeyTypeValueMeaning VARCHAR(80) NOT NULL
...

oms.KeyTypes 示例数据:

Id KeyTypeName         KeyTypeDescription
-- -----------         ------------------
1  RES_MFGS            Resource Manufacturers
2  RES_OWNERSHIP_TYPES Resource Ownership Types
...

oms.KeyTypeValues 示例数据:

Id KeyTypeId KeyTypeValueMeaning
-- --------- -------------------
1  1         Ford
2  1         Chevrolet
3  2         Owned
4  2         Leased
...

所以我的想法是我不必创建单独的ManufacturersOwnershipTypeModel 等表,因为除了它们的值之外,我们并不需要关于这些值的任何其他信息.目前我已经定义了大约 88 个,并且设计对我来说效果很好。

我正在处理一个问题查询,当从名为res.ResourceItems 的表加入时,它会给我带来性能问题。我必须将它加入KeyTypeValues 表 6 次以进行不同的查找。

ResourceItems 定义的一部分:

res.ResourceItems
-----------------
Id               INT NOT NULL IDENTITY(1,1) PRIMARY KEY
OwnsershipTypeId INT NOT NULL
ManufacturerId   INT NOT NULL
...

如果我消除了我的问题键类型 (RES_OWNERSHIP_TYPES),我可以完全打开它并在大约 17 秒内拉回约 112,000 行和 70 多列。性能不是很好,但考虑到我必须加入 9 个额外的表,这是可以接受的。但是,当我添加连接以检索 RES_OWNERSHIP_TYPES 时,执行时间会跳到 45 秒。 RES_OWNERSHIP_TYPES 键类型此时只有 3 个可能的值,oms.KeyTypeValues 总共只有大约 3,000 条记录。随着我们向正在构建的系统添加更多内容,它将随着时间的推移继续缓慢增长。

我意识到,将所有权类型拉出并创建一个enum 将是一种更有效的方式来处理这个问题,因为我们不太可能拥有更多的所有权类型;但是,我关心的是整体设计会带来如此巨大的性能冲击。

对于所有 Id 值,我确实有从 res.ResourceItemsoms.KeyTypeValues 的外键关系。我还在oms.KeyTypeValues.Id 列上设置了非唯一、非聚集索引。我已经重建它们以消除碎片。

作为测试,我在 res 架构中创建了单独的 KeyTypesKeyTypeValues 表,并仅加载了 RES_OWNERSHIP_TYPES 值并加入它,执行时间回到了大约 17 秒。我宁愿不执行此操作,因为它有点违背我的目的,并且似乎是在为更大的问题贴上创可贴。

我无法确定为什么仅通过该连接会产生如此大的影响,并希望有人能洞察我可能忽略的内容。如果需要,我很乐意分享更多的数据库设计。

【问题讨论】:

标签: sql-server tsql database-design sql-server-2014 query-performance


【解决方案1】:

如果将连接添加到具有 3 条记录的表会显着影响您的性能,这意味着查询计划会随着连接的添加而发生巨大变化。

尝试快速而肮脏的方法是运行一次sp_updatestats,看看是否能解决您的问题(我认为它很可能会解决)。这将告诉 SQL Server 更新所有表和索引的统计信息,并帮助它对查询计划做出更好的选择。

更彻底的解决方案是比较查询的两种变体的执行计划,以了解为什么性能会受到影响。这应该阐明如何提高性能。我不建议删除表格并进行纯代码枚举。如果一切正常,在加入那个额外的表时应该没有明显的性能差异。

【讨论】:

  • 你和@FLICKER 的建议我都做了,而且都有帮助。简单地运行sp_updatestats 影响最大,不到 20 秒。添加额外的索引和使用子查询又缩短了几秒钟,因此两个查询现在实际上是相同的。
【解决方案2】:

我建议你使用sub-query 而不是JOIN

有时如果查找表很小(就像您的查找表一样),sub-query 的工作速度比 JOIN 快​​

但是我们没有实际数据,也没有执行计划,因此您应该尝试不同的答案作为建议,看看哪一个适合您。

如果这不起作用,请尝试在引用字段上添加索引(除了引用的字段)。

顺便说一句,我不认为你的设计不好。我在许多不同的系统中都看到过这样的查找表。

【讨论】:

  • 谢谢 - 我希望我能将你和@Tim 都标记为答案;然而,更新统计数据似乎是最大的罪魁祸首。我尝试了子查询和附加索引,并且能够节省几秒钟的时间。感谢您对设计的评论 - 是的,我在不同的系统中使用过这种类型的设计,我认为它非常好。
  • 保持最新的统计数据总是一件好事。感谢您的投票:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-22
  • 1970-01-01
  • 1970-01-01
  • 2019-05-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多