我在一个web项目(asp.net)工作了大约六个月。最终产品即将上线。该项目使用SQL Server作为数据库。我们已经对一些大数据量进行了性能测试,结果表明,当数据变得太大时,性能会下降,比如200万行(超时问题、延迟响应等)。起初,我们使用的是完全规范化的数据库,但现在由于性能问题(为了减少连接),我们对其进行了部分规范化。首先,这是一个正确的决定吗?此外,随着未来客户端数量的增加,当数据大小变得非常大时,可能的解决方案是什么?
我想进一步补充:
- 200万行是实体表,解析关系的表有更大的行
- 当数据+用户数量增加时,性能会下降
- 在识别了大量使用的查询之后,进行了反规范化
- 我们还使用了大量的xml列和xquery。这会是原因吗
- 有点偏离主题,我的项目中的一些人说动态sql查询比存储过程方法更快。他们做了一些性能测试来证明他们的观点。我认为情况恰恰相反。一些频繁使用的查询是动态创建的,因为大多数其他查询都封装在存储过程中
在总体方案中,几百万行并不是一个特别大的数据库。
假设我们谈论的是OLTP数据库,在不首先确定瓶颈的根本原因的情况下进行去规范化是一个非常非常糟糕的想法。
您需要做的第一件事是在一个有代表性的时间段内分析查询工作负载,以确定大部分工作都在哪里完成(例如,如果您使用的是SQL Server,则使用SQL Profiler)。查看查询执行的逻辑读取次数乘以执行的次数。一旦确定了性能最差的前十个查询,就需要详细检查查询执行计划。
我将在这里冒险(因为通常是这样),但如果你的问题不是,我会感到惊讶
- 对于成本高昂的查询,缺少覆盖索引的"权利"
- 磁盘子系统配置不正确或指定不足
这个SO答案描述了如何对工作负载中执行最差的查询进行评测。
正如一句老话所说:"正常化直到它受伤,去规范化直到它起作用"。
我喜欢这个!这通常是一种不能再被接受的事情。我可以想象,在DBASEIII
时代,你一次不能打开超过4个表(除非更改一些AUTOEXEC.BAT参数并重新启动计算机,哈哈!…),人们对去规范化有一些兴趣。
但如今,我看到的这种解决方案类似于一个园丁等待海啸给他的草坪浇水。请使用可用的喷壶(SQL探查器)。
别忘了,每次你对数据库的一部分进行非规范化时,随着代码中错误风险的增加,你进一步调整它的能力就会降低,从而使整个系统的可持续性越来越低。
200万行通常不是超大数据库,这取决于您存储的信息类型。通常,当性能下降时,您应该验证您的索引策略。SQL Server数据库引擎优化顾问可能对此有所帮助。
这可能有一百万个原因;在进行"模式更改"之前,请使用SQL事件探查器和查询分析器来确定查询变慢的原因。您所需要做的就是创建几个索引并安排"更新统计信息",这并非不可能。。。但正如我所说,Profiler和Query Analyzer是了解正在发生的事情的最佳工具…
起初,我们使用的是完全规范化的数据库,但现在由于性能问题,我们使其部分规范化(以减少连接)。
正如一句老话所说:"正常化直到它受伤,去规范化直到它起作用"。
在大型、大量使用的dbs中,看到一定程度的非规范化以提高性能是很常见的,所以我现在不太担心它,只要你的性能仍然是你想要的,并且管理"非规范化"字段的代码不会变得太繁重。
随着未来客户端数量的增加,当数据大小变得非常大时,可能的解决方案是什么?
由于不太了解应用程序的域,很难说如何对其进行未来验证,但在流量很大的数据库中,将最近使用的数据和旧数据拆分为单独的表是一种相当常见的方法——如果95%的用户正在查询他们过去30/45天的数据,过去60天的数据和旧数据的"olddata"可以帮助您提高性能。
一个好主意是确保您设置了广泛的性能监控,这样您就可以在数据和负载增加时测量数据库的性能。如果您发现性能明显下降,可能是时候重新访问索引了!
这可能不是正确的决定。识别所有DB交互并独立分析它们,然后找到有问题的交互并制定策略以最大限度地提高性能。此外,打开数据库上的审计日志并对其进行挖掘可能会提供更好的优化点。
-
首先确保您的数据库相当健康,如果可能的话,在数据库上运行DBCC DBREINDEX,如果您负担不起性能损失,则运行DBCC INDEXDEFRAG并更新统计信息。
-
运行Profiler一段合理的采样时间,足以捕获大多数典型的函数,但过滤持续时间超过10秒的函数,你不在乎只需要几毫秒的事情,甚至不看这些。
-
既然你已经有了运行时间最长的查询,那么就把它们去掉;获取显示最多的,查看Query Analyzer中的执行计划,花一些时间了解它们,在必要的地方添加索引以加快检索
-
查看创建覆盖索引;如果需要,请更改应用程序,如果它正在执行SELECT*FROM。。。当它只需要SELECT LASTNAME、FIRSTNAME…时。。。。
-
重复探查器采样,持续时间为5秒、3秒等,直到性能达到您的预期。
我认为最好保持OLTP类型数据的非规范化,以防止核心数据被"污染"。那会把你咬得半死。
如果瓶颈是因为报告或只读需求,我个人认为除了标准化的"生产"表之外,还有非标准化的报告表没有问题;创建一个流程,将其汇总到所需的任何级别,以便快速查询。一个简单的SP或夜间进程周期性地汇总和取消规范化仅以只读方式使用的表,通常会对用户体验产生巨大影响。
毕竟,如果没有人想使用你的系统,因为它会变慢,那么拥有一组理论上干净、完美规范的数据有什么好处?
我们一直试图使用尽可能接近"真实世界"的数据库进行开发。这样就可以避免很多像这样的问题,因为如果任何ol’开发人员的连接在调试过程中不断超时,他都会发疯。调试Sql性能问题IMO的最佳方法是Mitch Wheat的建议;profile来查找有问题的脚本并从它们开始。优化脚本可以让您走得更远,然后您需要查看索引。还要确保Sql Server有足够的马力,尤其是IO(磁盘)非常重要。别忘了;缓存是王道。内存很便宜;购买更多。:)
你做任何有效的事情都是正确的
……只要你意识到以后可能会付出代价。听起来你无论如何都在考虑这个问题。
检查事项:
死锁
- 所有进程访问表的顺序是否相同
缓慢
- 是否有查询正在进行表扫描?
- 检查大型联接(超过4个表)
- 检查你的indees
请参阅我关于一般性能提示的其他帖子:
- 如何针对特定查询优化表
- 最受欢迎的性能调整技巧
在分析了索引和查询之后,您可能只想使用更多的硬件。再表演几场公羊可能会奏效。
有趣。。。这里有很多答案。。
rdbms/os版本是64位的吗?
在我看来,性能下降了好几倍。部分原因当然是由于索引。您是否考虑过以与数据存储方式一致的方式对某些表进行分区?也就是说,根据数据的进入方式(根据顺序)创建分区。这将大大提高性能,因为大多数索引都是静态的。
另一个问题是xml数据。您是否在使用xml索引?从书籍的第(2008)行"使用主XML索引,支持以下类型的辅助索引:PATH、VALUE和PROPERTY。"
最后,该系统目前设计用于运行/执行大量动态sql吗?如果是这样的话,你的记忆力会下降,因为计划需要生成、重新生成,很少再生成。我称之为记忆搅乱或记忆颠簸。
HTH
对于SQL Server来说,几百万条记录是一个很小的数据库。它可以通过大量的连接处理数兆字节的数据,而不需要费力。您可能有设计问题或编写的查询非常糟糕。
上线前的性能测试值得称赞。在你投入生产数月或数年后,修复这些东西要困难得多。
你所做的可能是一个糟糕的选择。如果取消规范化,则需要设置触发器以确保数据保持同步。是你干的吗?它增加了你的插入和更新时间多少?
我的第一个猜测是你没有在外键上加索引。
关于可能出错的其他猜测包括,过度使用以下内容:相关子查询纯量函数视图调用视图游标EAV表格缺乏可约束性选择*的使用
糟糕的桌子设计也会使它很难有好的性能。例如,如果表太宽,访问它们的速度会较慢。如果您经常将数据转换为另一种数据类型以使用它,那么您的数据存储不正确,这将始终拖累系统。
动态SQl可能比存储过程更快,也可能不是。这里没有一个正确的表演答案。为了内部安全(不必在表级别设置权限)和方便更改数据库,存储的proc更好。
您需要运行探查器并确定最慢的查询是什么。还要查看所有频繁运行的查询。当查询一天运行那么多次时,一个小的改变可以得到很大的回报。
你还应该去买一些关于性能调整的书。这些将帮助您完成整个过程,因为性能问题可能由许多因素引起:数据库设计查询设计硬件索引等
没有一个快速的解决方案,如果你不保持数据的完整性,随机去规范化会给你带来更多的麻烦。
首先,许多其他人都说几百万行不算大。我正在处理的当前应用程序有几个表,所有这些表都有超过一亿行,这些行都是标准化的。
我们确实遇到了一些性能不佳的问题,但这是由于使用了默认的表统计设置造成的。相对于表的总大小插入少量记录,即在包含1亿多条记录的表中插入100万条记录,并不会导致表统计信息的自动更新,因此我们会得到糟糕的查询计划,它表现为生成串行查询而不是并行查询。
至于去规范化是否是正确的决定,取决于您的模式。你是否必须定期执行深度查询,即加载联接以获取你经常需要访问的数据,如果是这样,那么部分去规范化可能是一种前进的方式。
但在此之前您已经检查了索引和表统计策略
检查您是否使用了合理的、结构良好的查询,以及您的联接是否格式良好。检查您的查询计划,确保您的查询实际上是按照您期望的方式进行解析的。
正如其他人所说,SQL事件探查器/数据库引擎优化顾问确实做得很好
对我来说,去规范化通常在我要做的事情列表的底部
如果您仍然有问题,请检查您的服务器软件和硬件设置。
- 您的数据库和日志文件是否位于使用分离物理磁盘单独的控制器
- 它有吗足够的内存
- 是否设置了日志文件签名?如果是的话,自动签名限制为低,即是否增长到经常