單數據庫vs多數據庫,單實例vs多實例 效率測試
最近公司的項目準備優化一下系統的性能,希望在數據庫方面看有沒有提升的空間,目前壓力測試發現數據庫服務器壓力還不夠大,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!========");
- }
#p#
下面是測試結果:
第一次,數據庫沒有創建索引,進行全表掃描:
- ------單數據庫,單線程測試---------
- 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機的計算負載太大,已經失去了測試的意義。
原文鏈接:http://www.cnblogs.com/bluedoctor/archive/2011/06/28/2092113.html
【編輯推薦】