单数据库vs多数据库,单实例vs多实例 效率测试

最近公司的项目准备优化一下系统的性能,希望在数据库方面看有没有提升的空间,目前压力测试发现数据库服务器压力还不够大,Web服务器压力也不是很大的情况下,前台页面访问却很慢,看有没有办法充分利用数据库服务器的性能,于是做了一个单数据库,多数据库,单实例,多实例不同情况下的数据访问效率测试。

测试环境:

  • CPU:Inter Core2 Quad,Q8300,2.50GHz;
  • 内存:4.00GB
  • 系统:Windows 7 32位系统
  • 数据库系统:SqlServer 2008,有两个实例,一个是默认实例,一个是命名实例QE2 

测试数据:

67万真实的基金收益数据,将这个表的数据放到了3个数据库中,详细内容见下面的连接字符串配置:

  1. <add name ="Ins1_DB1" connectionString ="Data Source=.;Initial Catalog=TestDB;Integrated Security=True"/>  
  2. <add name ="Ins1_DB2" connectionString ="Data Source=.;Initial Catalog=LocalDB;Integrated Security=True"/>  
  3. <add name ="Ins2_DB" connectionString ="Data Source=.\QE2;Initial Catalog=TestDB;Integrated Security=True"/>  

测试内容:

首先筛选出表中所有的基金代码,然后统计每只基金的最新收益率日期,对应的T-SQL代码如下:

  1.   declare @max_fsrq datetime  
  2.   declare @currJJDM varchar(10)  
  3.   declare @temp table (jjdm2 varchar(10))  
  4.   declare @useTime datetime  
  5.   set @useTime =GETDATE ();  
  6.     
  7.   insert into @temp(jjdm2)  
  8.    select jjdm from [FundYield] group by jjdm order by jjdm asc 
  9.      
  10.   while EXISTS (select jjdm2 from @temp)  
  11.   begin 
  12.     set @currJJDM=(select top 1 jjdm2 from @temp)  
  13.     select @max_fsrq = MAX(fsrq) from [FundYield] where jjdm=@currJJDM  
  14.     delete from @temp where jjdm2 =@currJJDM   
  15.     print @max_fsrq  
  16.   end 
  17.     
  18.  
  19. print 'T-SQL Execute Times(ms):'    
  20.  print datediff(ms,@useTime,getdate())  

直接执行这个T-SQL脚本,在数据库表没有索引的情况下,耗费的时间是: 

  1. T-SQL Execute Times(ms):  
  2. 58796 

根据这个功能,写了一个.net控制台程序来测试,测试程序没有使用任何数据访问框架,直接使用ADO.NET,下面是多线程测试的代码,其它代码略:

  1. public static void Test2(string connName1,string connName2)  
  2.        {  
  3.            System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();  
  4.            watch.Start();  
  5.            string allJjdmList = "";  
  6.            string connString = getConnectionString();  
  7.            //SqlConnection conn = new SqlConnection(connString);  
  8.            //conn.Open();  
  9.  
  10.            string sql = "select jjdm from [FundYield] group by jjdm order by jjdm asc";  
  11.            DataSet ds = getData(connString, sql);  
  12.            int allCount = ds.Tables[0].Rows.Count;  
  13.            int p = (int)(allCount * 0.5);  
  14.  
  15.            System.Threading.Thread t1=new System.Threading.Thread (new System.Threading.ParameterizedThreadStart (tp1=>  
  16.                {  
  17.                    for (int i = 0; i < p; i++)  
  18.                    {  
  19.                        string jjdm = ds.Tables[0].Rows[i][0].ToString();  
  20.  
  21.                        object result = getSclar(ConfigurationManager.ConnectionStrings[connName1].ConnectionString,  
  22.                       string.Format("select MAX(fsrq) from [FundYield] where jjdm='{0}'", jjdm));  
  23.                        if (result != DBNull.Value)  
  24.                        {  
  25.                            DateTime dt = Convert.ToDateTime(result);  
  26.                            //Console.WriteLine("Thread 2 No {0} ,jjdm[{1}] last FSRQ is:{2}", i, jjdm, dt);  
  27.                        }  
  28.  
  29.                        allJjdmList = allJjdmList + "," + jjdm;  
  30.                    }  
  31.  
  32.                    Console.WriteLine("Tread 1 used all time is(ms):{0}", watch.ElapsedMilliseconds);  
  33.                }  
  34.            ));  
  35.  
  36.            System.Threading.Thread t2 = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(tp2 =>  
  37.            {  
  38.                for (int i = p; i < allCount; i++)  
  39.                {  
  40.                    string jjdm = ds.Tables[0].Rows[i][0].ToString();  
  41.                    //这里不论使用default还是express,区别不大  
  42.                    object result = getSclar(ConfigurationManager.ConnectionStrings[connName2].ConnectionString,  
  43.                        string.Format("select MAX(fsrq) from [FundYield] where jjdm='{0}'", jjdm));  
  44.                    if (result != DBNull.Value)  
  45.                    {  
  46.                        DateTime dt = Convert.ToDateTime(result);  
  47.                        //Console.WriteLine("Thread 2 No {0} ,jjdm[{1}] last FSRQ is:{2}", i, jjdm, dt);  
  48.                    }  
  49.                      
  50.                    allJjdmList = allJjdmList + "," + jjdm;  
  51.                }  
  52.  
  53.                Console.WriteLine("Tread 2 used all time is(ms):{0}", watch.ElapsedMilliseconds);  
  54.            }  
  55.            ));  
  56.  
  57.            t1.Start();  
  58.            t2.Start();  
  59.            t1.Join();  
  60.            t2.Join();  
  61.  
  62.            Console.WriteLine("====All thread completed!========");  
  63.  
  64.        } 

#p#

下面是测试结果:

第一次,数据库没有创建索引,进行全表扫描:

  1. ------单数据库,单线程测试---------  
  2. used all time is(ms):59916  
  3. ------同一实例,双数据库,单线程测试---------  
  4. used all time is(ms):59150  
  5. ------同一实例,双数据库,多线程测试---------  
  6. Tread 2 used all time is(ms):51223  
  7. Tread 1 used all time is(ms):58175  
  8. ====All thread completed!========  
  9. ------双实例,双数据库,单线程测试---------  
  10. used all time is(ms):58230  
  11. ------双实例,双数据库,多线程测试---------  
  12. Tread 2 used all time is(ms):52705  
  13. Tread 1 used all time is(ms):58293  
  14. ====All thread completed!======== 

第二次,数据库响应的字段创建索引,下面是测试结果:

  1. ------单数据库,单线程测试---------  
  2. used all time is(ms):1721  
  3. ------同一实例,双数据库,单线程测试---------  
  4. used all time is(ms):1737  
  5. ------同一实例,双数据库,多线程测试---------  
  6. Tread 2 used all time is(ms):1684  
  7. Tread 1 used all time is(ms):1714  
  8. ====All thread completed!========  
  9. ------双实例,双数据库,单线程测试---------  
  10. used all time is(ms):1874  
  11.  
  12.  
  13. ------单数据库,单线程测试---------  
  14. used all time is(ms):1699  
  15. ------同一实例,双数据库,单线程测试---------  
  16. used all time is(ms):1754  
  17. ------同一实例,双数据库,多线程测试---------  
  18. Tread 1 used all time is(ms):1043  
  19. Tread 2 used all time is(ms):1103  
  20. ====All thread completed!========  
  21. ------双实例,双数据库,单线程测试---------  
  22. used all time is(ms):1838  
  23. ------双实例,双数据库,多线程测试---------  
  24. Tread 1 used all time is(ms):1072  
  25. Tread 2 used all time is(ms):1139  
  26. ====All thread completed!======== 

测试结论:

综合全表扫描访问和有索引方式的访问,

单线程访问:

  • 在同一个数据库实例上,双数据库没有体现出优势,甚至单数据库稍微优胜于多数据库;
  • 在两个数据库实例上,双实例双实例要落后于单实例单数据库;

多线程访问:

  • 双数据库实例稍微落后于单数据库实例;

综合结论,看来不论是双数据库还是双实例,对比与单实例或者单数据库,都没有体现出优势,看来前者的优势不在于访问效率,一位朋友说,数据库实例是不同的服务,控制粒度更小,维护影响比较低。但我想,双数据库实例,双数据库,多核CPU,应该跟两台数据库服务器差不多的性能吧,怎么没有体现优势呢?也许是我的测试机器仅仅有一个磁盘,这里磁盘IO成了瓶颈。

这个测试有没有意义,或者这个结果的原因,还请大牛们多多指教!

意外发现:

1,有人说频繁的查询在完全数据库中进行效率最高,测试发现,在查询分析器上直接运行上面的那个T-SQL脚本,跟程序从数据库取出数据,再加工计算查询,效率上没有明显的区别,所以哪些支持“将复杂的业务逻辑写在存储过程中效率最高的观点是站不住脚的!”  ,ADO.NET从数据库来回操作数据一样有效率,如果加上复杂的字符函数计算和大批量的循环操作,存储过程的效率不一定高。

2,在使用程序进行频繁的数据库操作的时候,使用一个连接对象还是在每个方法中使用新的连接对象,一直是很纠结的问题,心想频繁的数据操作还是用一个连接对象快吧?在本文给出的测试代码中,有下列语句:

  1. //SqlConnection conn = new SqlConnection(connString);  
  2.             //conn.Open(); 

注释掉这些语句,在被调用的方法中使用自己的连接对象,与取消注释,全部使用一个连接对象,效率上没有任何区别!

究其原因,可能是ADO.NET自动使用了连接池,实际上程序在不同的情况下,使用的都是一个连接,所以操作上效率没有区别。

后续测试

在真正的服务器上进行测试,发现测试结论又不一样,我们有服务器A,拥有16个核,32G内存,另外一台服务器B,拥有8个核,16G内存。在服务器A上有一个SqlServer实例,两个一样的数据库;在在服务器B上有一个SqlServer实例,一个数据库,下面是测试结果:

  1. ------单数据库,单线程测试---------  
  2. used all time is(ms):650  
  3. ------同一实例,双数据库,单线程测试---------  
  4. used all time is(ms):418  
  5. ------同一实例,双数据库,多线程测试---------  
  6. Tread 2 used all time is(ms):221  
  7. Tread 1 used all time is(ms):223  
  8. ====All thread completed!========  
  9. ------双实例,双数据库,单线程测试---------  
  10. used all time is(ms):1283  
  11. ------双实例,双数据库,多线程测试---------  
  12. Tread 1 used all time is(ms):228  
  13. Tread 2 used all time is(ms):542  
  14. ====All thread completed!======== 

可以看到,同一实例,多数据库,还是有明显的优势,而多线程优势更大;由于两台服务器性能差距较大,双实例测试没有显示出优势,但多线程下还是比单实例单数据库好!

为什么PC机跟服务器测试的结论不一致?也许还是跟计算能力相关,PC机的计算负载太大,已经失去了测试的意义。

原文链接:http://www.cnblogs.com/bluedoctor/archive/2011/06/28/2092113.html

【编辑推荐】

  1. 说说Top子句对查询计划的影响
  2. SQL Server复灾 你懂了吗?
  3. SQL Server管理 这些你懂吗?
  4. 手把手教你建立SQL数据库的表分区
  5. 如何设计合理的多表关联的表分区

文章来源网络,作者:运维,如若转载,请注明出处:https://shuyeidc.com/wp/284435.html<

(0)
运维的头像运维
上一篇2025-05-14 10:02
下一篇 2025-05-14 10:03

相关推荐

  • 个人主题怎么制作?

    制作个人主题是一个将个人风格、兴趣或专业领域转化为视觉化或结构化内容的过程,无论是用于个人博客、作品集、社交媒体账号还是品牌形象,核心都是围绕“个人特色”展开,以下从定位、内容规划、视觉设计、技术实现四个维度,详细拆解制作个人主题的完整流程,明确主题定位:找到个人特色的核心主题定位是所有工作的起点,需要先回答……

    2025-11-20
    0
  • 社群营销管理关键是什么?

    社群营销的核心在于通过建立有温度、有价值、有归属感的社群,实现用户留存、转化和品牌传播,其管理需贯穿“目标定位-内容运营-用户互动-数据驱动-风险控制”全流程,以下从五个维度展开详细说明:明确社群定位与目标社群管理的首要任务是精准定位,需明确社群的核心价值(如行业交流、产品使用指导、兴趣分享等)、目标用户画像……

    2025-11-20
    0
  • 香港公司网站备案需要什么材料?

    香港公司进行网站备案是一个涉及多部门协调、流程相对严谨的过程,尤其需兼顾中国内地与香港两地的监管要求,由于香港公司注册地与中国内地不同,其网站若主要服务内地用户或使用内地服务器,需根据服务器位置、网站内容性质等,选择对应的备案路径(如工信部ICP备案或公安备案),以下从备案主体资格、流程步骤、材料准备、注意事项……

    2025-11-20
    0
  • 如何企业上云推广

    企业上云已成为数字化转型的核心战略,但推广过程中需结合行业特性、企业痛点与市场需求,构建系统性、多维度的推广体系,以下从市场定位、策略设计、执行落地及效果优化四个维度,详细拆解企业上云推广的实践路径,精准定位:明确目标企业与核心价值企业上云并非“一刀切”的方案,需先锁定目标客户群体,提炼差异化价值主张,客户分层……

    2025-11-20
    0
  • PS设计搜索框的实用技巧有哪些?

    在PS中设计一个美观且功能性的搜索框需要结合创意构思、视觉设计和用户体验考量,以下从设计思路、制作步骤、细节优化及交互预览等方面详细说明,帮助打造符合需求的搜索框,设计前的规划明确使用场景:根据网站或APP的整体风格确定搜索框的调性,例如极简风适合细线条和纯色,科技感适合渐变和发光效果,电商类则可能需要突出搜索……

    2025-11-20
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注