SQL Server性能调优——报表数据库与业务数据库分离
[2] SQL Server性能调优——报表数据库与业务数据库分离
前段时间把公司的主数据库切了,分成业务库和报表库,业务库向报表库进行实时的Replication。这个项目的上线提升了系统的性能和可维护性,现在把设计时的考量和所做的工作重新回顾一下,作为备忘。
项目起源
在日常的开发过程中,功能总是先于性能被考虑。只有当用户抱怨系统性能时,我们才开始头痛医头,脚痛医脚地来解决这些性能问题。
公司的CRM和ERP系统叫作Olite,完全是我们组开发的。从无到有,功能不断扩展,原先只有CRM模块,后来加入了ERP模块,Accounting功能和Report功能。近来出现的情况是当某些用户跑一个大Report时,正在进行业务操作的用户感觉系统响应非常慢。通过对系统的性能监视发现,在这些时刻,数据库中产生了大量的锁,同时服务器上出现了CPU和内存资源消耗的尖峰。
系统结构
性能问题源于系统的整体结构和发展过程。Olite系统的Application是基于.NET平台的Web Form程序,数据库为SQL Server 2005。其主体结构如下图所示:
其Application端包括两个网站:OliteBase和OliteReport,但连接的都是同一个数据库。
Olite的Application端其实很薄,而把大量的业务逻辑包装在存储过程中,放在数据库端来运行。
这种结构在起初性能很好,而且提供给用户的Report是实时的业务数据。但随着提供的业务模块,特别是Report的增多(Report对应的存储过程连接的表多,计算量大,输出的结果集大),数据库就成为了瓶颈。
首先,我们做了存储过程的优化,通过创建Trace捕获性能差的存储过程,并对其进行优化。我们这么做了一段时间,但获得的收效并不大。我们在优化以往存储过程的同时,随着系统新功能的上线,又有新的存储过程进入需要优化的列表中。
其次,修改数据库设计,其中包括修改表结构和优化索引。在系统局部重构表结构与关系对于性能的提升还是比较明显的,但这样的修改会造成Application端的大量修改,工作量大,风险大,所以不能大规模实施。对于索引优化又存在矛盾,业务模块(OliteBase)要求数据库中的索引不要太多,以支持高效的插入、修改和删除,而报表模块(OliteReport)则希望在数据库中有更多的索引,以支持高效读。
最后,我们还试图提供晚一天的Report服务,来分流主数据库的压力。每天通过把前一天的备份数据库恢复在另一台服务器上,并在此服务器上提供OliteReport2站点,给用户提供Report服务。但用户并不喜欢使用OliteReport2,原因分析下来有3个方面:其一,有时用户确实需要实时的Report。其二,OliteReport能存储用户的Report条件,而OliteReport2由于每天都会被刷新,无法保留这些条件。其三,用户更习惯打开原来的Report链接。
项目需求
上述的各种优化方案都没有根本性的解决系统的性能问题。在这种的背景下我们有了把报表数据库与业务数据库分离的想法。
此项目的需求:
1. 提高用户对整个系统性能的感受,Report模块不要影响到业务模块的运行。
2. 用户可以和原先一样使用Report模块,即不增加新的Report站点。
3. 用户可以和原先一样存储填写的Report条件,以供重复使用。
4. 尽可能提供最小延时的Report。
需求1是这个项目的主要目标,需求2、3、4是尽可能保证项目所带来的改变对用户是透明的。