单数据库,多数据库,单实例,多实例不同情况下的数据访问效率测试

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

测试环境:

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

测试数据:

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

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

测试内容:

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

declare @max_fsrq datetime
  declare @currJJDM varchar(10)
  declare @temp table (jjdm2 varchar(10))
  declare @useTime datetime
  set @useTime =GETDATE ();
  
  insert into @temp(jjdm2)
   select jjdm from [FundYield] group by jjdm order by jjdm asc
   
  while EXISTS (select jjdm2 from @temp)
  begin
    set @currJJDM=(select top 1 jjdm2 from @temp)
    select @max_fsrq = MAX(fsrq) from [FundYield] where jjdm=@currJJDM
    delete from @temp where jjdm2 =@currJJDM 
    print @max_fsrq
  end
  
print 'T-SQL Execute Times(ms):'  
 print datediff(ms,@useTime,getdate())

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

T-SQL Execute Times(ms): 58796

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

public static void Test2(string connName1,string connName2)
        {
            System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
            watch.Start();
            string allJjdmList = "";
            string connString = getConnectionString();
            //SqlConnection conn = new SqlConnection(connString);
            //conn.Open();
            string sql = "select jjdm from [FundYield] group by jjdm order by jjdm asc";
            DataSet ds = getData(connString, sql);
            int allCount = ds.Tables[0].Rows.Count;
            int p = (int)(allCount * 0.5);
            System.Threading.Thread t1=new System.Threading.Thread (new System.Threading.ParameterizedThreadStart (tp1=>
                {
                    for (int i = 0; i < p; i++)
                    {
                        string jjdm = ds.Tables[0].Rows[i][0].ToString();
                        object result = getSclar(ConfigurationManager.ConnectionStrings[connName1].ConnectionString,
                       string.Format("select MAX(fsrq) from [FundYield] where jjdm='{0}'", jjdm));
                        if (result != DBNull.Value)
                        {
                            DateTime dt = Convert.ToDateTime(result);
                            //Console.WriteLine("Thread 2 No {0} ,jjdm[{1}] last FSRQ is:{2}", i, jjdm, dt);
                        }
                        allJjdmList = allJjdmList + "," + jjdm;
                    }
                    Console.WriteLine("Tread 1 used all time is(ms):{0}", watch.ElapsedMilliseconds);
                }
            ));
            System.Threading.Thread t2 = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(tp2 =>
            {
                for (int i = p; i < allCount; i++)
                {
                    string jjdm = ds.Tables[0].Rows[i][0].ToString();
                    //这里不论使用default还是express,区别不大
                    object result = getSclar(ConfigurationManager.ConnectionStrings[connName2].ConnectionString,
                        string.Format("select MAX(fsrq) from [FundYield] where jjdm='{0}'", jjdm));
                    if (result != DBNull.Value)
                    {
                        DateTime dt = Convert.ToDateTime(result);
                        //Console.WriteLine("Thread 2 No {0} ,jjdm[{1}] last FSRQ is:{2}", i, jjdm, dt);
                    }
                    
                    allJjdmList = allJjdmList + "," + jjdm;
                }
                Console.WriteLine("Tread 2 used all time is(ms):{0}", watch.ElapsedMilliseconds);
            }
            ));
            t1.Start();
            t2.Start();
            t1.Join();
            t2.Join();
            Console.WriteLine("====All thread completed!========");
        }

下面是测试结果:

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

------单数据库,单线程测试--------- used all time is(ms):59916 ------同一实例,双数据库,单线程测试--------- used all time is(ms):59150 ------同一实例,双数据库,多线程测试--------- Tread 2 used all time is(ms):51223 Tread 1 used all time is(ms):58175 ====All thread completed!======== ------双实例,双数据库,单线程测试--------- used all time is(ms):58230 ------双实例,双数据库,多线程测试--------- Tread 2 used all time is(ms):52705 Tread 1 used all time is(ms):58293 ====All thread completed!========

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

------单数据库,单线程测试--------- used all time is(ms):1721 ------同一实例,双数据库,单线程测试--------- used all time is(ms):1737 ------同一实例,双数据库,多线程测试--------- Tread 2 used all time is(ms):1684 Tread 1 used all time is(ms):1714 ====All thread completed!======== ------双实例,双数据库,单线程测试--------- used all time is(ms):1874

------单数据库,单线程测试--------- used all time is(ms):1699 ------同一实例,双数据库,单线程测试--------- used all time is(ms):1754 ------同一实例,双数据库,多线程测试--------- Tread 1 used all time is(ms):1043 Tread 2 used all time is(ms):1103 ====All thread completed!======== ------双实例,双数据库,单线程测试--------- used all time is(ms):1838 ------双实例,双数据库,多线程测试--------- Tread 1 used all time is(ms):1072 Tread 2 used all time is(ms):1139 ====All thread completed!========

测试结论:

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

单线程访问:

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

多线程访问:

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

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

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

--------------------------------------------------------------

意外发现:

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

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

//SqlConnection conn = new SqlConnection(connString); //conn.Open(); 注释掉这些语句,在被调用的方法中使用自己的连接对象,与取消注释,全部使用一个连接对象,效率上没有任何区别!

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

后续测试

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

------单数据库,单线程测试--------- used all time is(ms):650 ------同一实例,双数据库,单线程测试--------- used all time is(ms):418 ------同一实例,双数据库,多线程测试--------- Tread 2 used all time is(ms):221 Tread 1 used all time is(ms):223 ====All thread completed!======== ------双实例,双数据库,单线程测试--------- used all time is(ms):1283 ------双实例,双数据库,多线程测试--------- Tread 1 used all time is(ms):228 Tread 2 used all time is(ms):542 ====All thread completed!========

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

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏点滴积累

geotrellis使用(三十九)COG 写入更新

前言 前面介绍过了如何在 ETL 的时候更新 Layer,使得能够在大数据量的时候完成 ETL 操作,同时前两篇文章也介绍了 COG 以及如何在 Geotrel...

41612
来自专栏Spark生态圈

spark任务之Task失败监控

在spark程序中,task有失败重试机制(根据 spark.task.maxFailures 配置,默认是4次),当task执行失败时,并不会直接导致整个应用...

4353
来自专栏大史住在大前端

一统江湖的大前端(4)shell.js——穿上马甲我照样认识你

码农界存在着无数条鄙视链,linux使用者对windows的鄙视便是其中之一,cli使用者对GUI用户的嘲讽也是如此,在这样一个讲究逼格的时代,如果你的桌面上没...

2005
来自专栏杨建荣的学习笔记

gqlplus的简单使用(r6笔记第43天)

使用sqlplus的时候如果命令敲错之后,可能很多情况下需要重新再敲一遍,也可以用一些快捷方式,但是如果想查看之前执行的sql语句,list选项就无能为力了,它...

3089
来自专栏依乐祝

.NET Core开发者的福音之玩转Redis的又一傻瓜式神器推荐

为什么写这篇文章呢?因为.NET Core的生态越来越好了!之前玩转.net的时候操作Redis相信大伙都使用过一些组件,但都有一些缺点,如ServiceSta...

992
来自专栏逍遥剑客的游戏开发

基于Unity的编辑器开发(二): 进程间通信

先要做的, 是需要编辑器和Unity共享一部部分代码, 至少协议定义和解析我不想写两遍. 虽然有protobuf这样的工具库, 但是如果不是跨语言的话, 我觉得...

51816
来自专栏程序员的SOD蜜

“设计应对变化”--实例讲解一个数据同步系统

 系列文章索引: [WCF邮件通信系统应用 之 数据同步程序 之 设计内幕 之 一] 同步一个数据库要发多少个数据包? [WCF邮件通信系统应用 之 数据同步...

2527
来自专栏24K纯开源

用Qt写软件系列二:QCookieViewer(浏览器Cookie查看器)

预备     继上篇《浏览器缓存查看器QCacheViewer》之后,本篇开始QCookieViewer的编写。Cookie技术作为网站收集用户隐私信息、分析用...

2486
来自专栏阿北的知识分享

yii2开发中19条推荐实践

这个是做yii2开发的基石,除非没有办法使用,否则请不要放弃,除了更容易的安装yii2及第三方扩展外,能使用Composer代表着你的服务器最少能运行起来php...

3836
来自专栏星回的实验室

golang建立MongoDB连接池

最近用go语言重构之前用python草草搭建的推荐引擎,语言杂食确实很难受,不过不得不说,在饱受弱类型脚本语言的摧残之后重新用回强类型语言,轻微强迫症的我居然还...

2015

扫码关注云+社区

领取腾讯云代金券