ADO.NET數(shù)據(jù)連接池剖析
更新時(shí)間:2012年11月21日 16:11:55 作者:
本篇文章起源于在GCR MVP Open Day的時(shí)候和C# MVP討論連接池的概念而來(lái)的。因此單獨(dú)寫(xiě)一篇文章剖析一下連接池
本篇文章起源于在GCR MVP Open Day的時(shí)候和C# MVP張響討論連接池的概念而來(lái)的。因此單獨(dú)寫(xiě)一篇文章剖析一下連接池。
為什么需要連接池
剖析一個(gè)技術(shù)第一個(gè)要問(wèn)的是,這項(xiàng)技術(shù)為什么存在。
對(duì)于每一個(gè)到SQL Server的連接,都需要經(jīng)歷TCP/IP協(xié)議的三次握手,身份認(rèn)證,在SQL Server里建立連接,分配資源等。而當(dāng)客戶(hù)端關(guān)閉連接時(shí),客戶(hù)端就會(huì)和SQL Server終止物理連接。但是,我們做過(guò)數(shù)據(jù)庫(kù)開(kāi)發(fā)的人都知道,每次操作完后關(guān)閉連接是再正常不過(guò)的事了,一個(gè)應(yīng)用程序即使在負(fù)載不大的情況下也需要不停的連接SQL Server和關(guān)閉連接,同一個(gè)應(yīng)用程序同時(shí)也可能存在多個(gè)連接。
因此,如果不斷的這樣建立和關(guān)閉連接,會(huì)是非常浪費(fèi)資源的做法。因此Ado.net中存在連接池這種機(jī)制。在對(duì)SQL Server來(lái)說(shuō)的客戶(hù)端的應(yīng)用程序進(jìn)程中維護(hù)連接池。統(tǒng)一管理Ado.net和SQL Server的連接,既連接池保持和SQL Server的連接,當(dāng)Connection.Open()時(shí),僅僅從連接池中分配一個(gè)已經(jīng)和SQL Server建立的連接,當(dāng)Connection.Close()時(shí),也并不是和SQL Server物理斷開(kāi)連接,僅僅是將連接進(jìn)行回收。
因此,連接池總是能維護(hù)一定數(shù)量的和SQL Server的連接,以便應(yīng)用程序反復(fù)使用這些連接以減少性能損耗。
重置連接的sys.sp_reset_connection
連接是有上下文的,比如說(shuō)當(dāng)前連接有未提交的事務(wù),存在可用的游標(biāo),存在對(duì)應(yīng)的臨時(shí)表。因此為了便于連接重復(fù)使用,使得下一個(gè)連接不會(huì)收到上一個(gè)連接的影響,SQL Server通過(guò)sys.sp_reset_connection來(lái)清除當(dāng)前連接的上下文,以便另一個(gè)連接繼續(xù)使用。
當(dāng)在Ado.net中調(diào)用了Connection.Close()時(shí),會(huì)觸發(fā)sys.sp_reset_connection。這個(gè)系統(tǒng)存儲(chǔ)過(guò)程大概會(huì)做如下事情:
關(guān)閉游標(biāo)
清除臨時(shí)對(duì)象,比如臨時(shí)表
釋放鎖
重置Set選項(xiàng)
重置統(tǒng)計(jì)信息
回滾未提交的事務(wù)
切換到連接的默認(rèn)數(shù)據(jù)庫(kù)
重置Trace Flag
此外,根據(jù)BOL上的信息:
"The sp_reset_connection stored procedure is used by SQL
Server to support remote stored procedure calls in a transaction. This stored
procedure also causes Audit Login and Audit Logout events to fire when a
connection is reused from a connection pool."
可以知道不能顯式的在SQL Server中調(diào)用sys.sp_reset_connection,此外,這個(gè)方法還會(huì)觸發(fā)Audit Login和Audit Logout事件。
一個(gè)簡(jiǎn)單的示例
下面我們通過(guò)一個(gè)簡(jiǎn)單的示例來(lái)看連接池的使用:
首先我分別使用四個(gè)連接,其中第一個(gè)和第二個(gè)連接之間有10秒的等待時(shí)間:
String ConnectionString = "data source=.\\sql2012;database=AdventureWorks;uid=sa;pwd=sasasa";
SqlConnection cn1=new SqlConnection(ConnectionString);
SqlCommand cmd1=cn1.CreateCommand();
cmd1.CommandText="SELECT * FROM dbo.ABCD";
cn1.Open();
cmd1.ExecuteReader();
cn1.Close();
Response.Write("連接關(guān)閉時(shí)間:"+DateTime.Now.ToLongTimeString()+"<br />");
System.Threading.Thread.Sleep(10000);
SqlConnection cn2=new SqlConnection(ConnectionString);
SqlCommand cmd2=cn2.CreateCommand();
cmd2.CommandText="SELECT * FROM dbo.ABCD";
cn2.Open();
cmd2.ExecuteReader();
cn2.Close();
Response.Write("連接關(guān)閉時(shí)間:"+DateTime.Now.ToLongTimeString()+"<br />");
SqlConnection cn3=new SqlConnection(ConnectionString);
SqlCommand cmd3=cn3.CreateCommand();
cmd3.CommandText="SELECT * FROM dbo.ABCD";
cn3.Open();
cmd3.ExecuteReader();
cn3.Close();
Response.Write("連接關(guān)閉時(shí)間:"+DateTime.Now.ToLongTimeString()+"<br />");
System.Threading.Thread.Sleep(1500);
SqlConnection cn4=new SqlConnection(ConnectionString);
SqlCommand cmd4=cn4.CreateCommand();
cmd4.CommandText="SELECT * FROM dbo.ABCD";
cn4.Open();
cmd4.ExecuteReader();
cn4.Close();
Response.Write("連接關(guān)閉時(shí)間:"+DateTime.Now.ToLongTimeString()+"<br />");
下面我們通過(guò)Profile截圖:
我們首先可以看到,每一次Close()方法都會(huì)觸發(fā)exec sp_reset_connection
此外,我們?cè)谥虚g等待的10秒還可以看到SP51是不斷的,剩下幾個(gè)連接全部用的是SPID51這個(gè)連接,雖然Ado.net Close了好幾次,但實(shí)際上物理連接是沒(méi)有中斷的。
因此可以看出,連接池大大的提升了效率。
為什么需要連接池
剖析一個(gè)技術(shù)第一個(gè)要問(wèn)的是,這項(xiàng)技術(shù)為什么存在。
對(duì)于每一個(gè)到SQL Server的連接,都需要經(jīng)歷TCP/IP協(xié)議的三次握手,身份認(rèn)證,在SQL Server里建立連接,分配資源等。而當(dāng)客戶(hù)端關(guān)閉連接時(shí),客戶(hù)端就會(huì)和SQL Server終止物理連接。但是,我們做過(guò)數(shù)據(jù)庫(kù)開(kāi)發(fā)的人都知道,每次操作完后關(guān)閉連接是再正常不過(guò)的事了,一個(gè)應(yīng)用程序即使在負(fù)載不大的情況下也需要不停的連接SQL Server和關(guān)閉連接,同一個(gè)應(yīng)用程序同時(shí)也可能存在多個(gè)連接。
因此,如果不斷的這樣建立和關(guān)閉連接,會(huì)是非常浪費(fèi)資源的做法。因此Ado.net中存在連接池這種機(jī)制。在對(duì)SQL Server來(lái)說(shuō)的客戶(hù)端的應(yīng)用程序進(jìn)程中維護(hù)連接池。統(tǒng)一管理Ado.net和SQL Server的連接,既連接池保持和SQL Server的連接,當(dāng)Connection.Open()時(shí),僅僅從連接池中分配一個(gè)已經(jīng)和SQL Server建立的連接,當(dāng)Connection.Close()時(shí),也并不是和SQL Server物理斷開(kāi)連接,僅僅是將連接進(jìn)行回收。
因此,連接池總是能維護(hù)一定數(shù)量的和SQL Server的連接,以便應(yīng)用程序反復(fù)使用這些連接以減少性能損耗。
重置連接的sys.sp_reset_connection
連接是有上下文的,比如說(shuō)當(dāng)前連接有未提交的事務(wù),存在可用的游標(biāo),存在對(duì)應(yīng)的臨時(shí)表。因此為了便于連接重復(fù)使用,使得下一個(gè)連接不會(huì)收到上一個(gè)連接的影響,SQL Server通過(guò)sys.sp_reset_connection來(lái)清除當(dāng)前連接的上下文,以便另一個(gè)連接繼續(xù)使用。
當(dāng)在Ado.net中調(diào)用了Connection.Close()時(shí),會(huì)觸發(fā)sys.sp_reset_connection。這個(gè)系統(tǒng)存儲(chǔ)過(guò)程大概會(huì)做如下事情:
關(guān)閉游標(biāo)
清除臨時(shí)對(duì)象,比如臨時(shí)表
釋放鎖
重置Set選項(xiàng)
重置統(tǒng)計(jì)信息
回滾未提交的事務(wù)
切換到連接的默認(rèn)數(shù)據(jù)庫(kù)
重置Trace Flag
此外,根據(jù)BOL上的信息:
復(fù)制代碼 代碼如下:
"The sp_reset_connection stored procedure is used by SQL
Server to support remote stored procedure calls in a transaction. This stored
procedure also causes Audit Login and Audit Logout events to fire when a
connection is reused from a connection pool."
可以知道不能顯式的在SQL Server中調(diào)用sys.sp_reset_connection,此外,這個(gè)方法還會(huì)觸發(fā)Audit Login和Audit Logout事件。
一個(gè)簡(jiǎn)單的示例
下面我們通過(guò)一個(gè)簡(jiǎn)單的示例來(lái)看連接池的使用:
首先我分別使用四個(gè)連接,其中第一個(gè)和第二個(gè)連接之間有10秒的等待時(shí)間:
復(fù)制代碼 代碼如下:
String ConnectionString = "data source=.\\sql2012;database=AdventureWorks;uid=sa;pwd=sasasa";
SqlConnection cn1=new SqlConnection(ConnectionString);
SqlCommand cmd1=cn1.CreateCommand();
cmd1.CommandText="SELECT * FROM dbo.ABCD";
cn1.Open();
cmd1.ExecuteReader();
cn1.Close();
Response.Write("連接關(guān)閉時(shí)間:"+DateTime.Now.ToLongTimeString()+"<br />");
System.Threading.Thread.Sleep(10000);
SqlConnection cn2=new SqlConnection(ConnectionString);
SqlCommand cmd2=cn2.CreateCommand();
cmd2.CommandText="SELECT * FROM dbo.ABCD";
cn2.Open();
cmd2.ExecuteReader();
cn2.Close();
Response.Write("連接關(guān)閉時(shí)間:"+DateTime.Now.ToLongTimeString()+"<br />");
SqlConnection cn3=new SqlConnection(ConnectionString);
SqlCommand cmd3=cn3.CreateCommand();
cmd3.CommandText="SELECT * FROM dbo.ABCD";
cn3.Open();
cmd3.ExecuteReader();
cn3.Close();
Response.Write("連接關(guān)閉時(shí)間:"+DateTime.Now.ToLongTimeString()+"<br />");
System.Threading.Thread.Sleep(1500);
SqlConnection cn4=new SqlConnection(ConnectionString);
SqlCommand cmd4=cn4.CreateCommand();
cmd4.CommandText="SELECT * FROM dbo.ABCD";
cn4.Open();
cmd4.ExecuteReader();
cn4.Close();
Response.Write("連接關(guān)閉時(shí)間:"+DateTime.Now.ToLongTimeString()+"<br />");
下面我們通過(guò)Profile截圖:

我們首先可以看到,每一次Close()方法都會(huì)觸發(fā)exec sp_reset_connection
此外,我們?cè)谥虚g等待的10秒還可以看到SP51是不斷的,剩下幾個(gè)連接全部用的是SPID51這個(gè)連接,雖然Ado.net Close了好幾次,但實(shí)際上物理連接是沒(méi)有中斷的。
因此可以看出,連接池大大的提升了效率。
相關(guān)文章
SQL Server實(shí)現(xiàn)跨庫(kù)跨服務(wù)器訪(fǎng)問(wèn)的方法
這篇文章主要給大家介紹了關(guān)于SQL Server實(shí)現(xiàn)跨庫(kù)跨服務(wù)器訪(fǎng)問(wèn)的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用SQL Server具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06SQL Server 公用表表達(dá)式(CTE)實(shí)現(xiàn)遞歸的方法
這篇文章主要介紹了SQL Server 公用表表達(dá)式(CTE)實(shí)現(xiàn)遞歸的方法,需要的朋友可以參考下2017-05-05Sql Server:多行合并成一行,并做分組統(tǒng)計(jì)的兩個(gè)方法
Sql Server:多行合并成一行,并做分組統(tǒng)計(jì)的兩個(gè)方法,需要的朋友可以參考一下2013-02-02sql 判斷數(shù)據(jù)庫(kù),表,存儲(chǔ)過(guò)程等是否存在的代碼
sql下用了判斷各種資源是否存在的代碼,很實(shí)用。需要的朋友可以參考下。2009-12-12如何在SQLSERVER中快速有條件刪除海量數(shù)據(jù)
如何在SQLSERVER中快速有條件刪除海量數(shù)據(jù)...2006-09-09SQL查詢(xún)某列指定長(zhǎng)度的字符串多余的用省略號(hào)來(lái)表示
有時(shí)候?yàn)榱嗣烙^,只需要顯示前面幾個(gè)字符串,剩下的可以用省略號(hào)來(lái)表示,下面有個(gè)不錯(cuò)的示例,感興趣的朋友可以參考下2013-11-11SQL Server常見(jiàn)問(wèn)題及解決方法分享
這篇文章主要為大家詳細(xì)介紹了SQL Server常見(jiàn)問(wèn)題及解決方法,包括SQL Server連接問(wèn)題,SQL Server日志問(wèn)題,SQL Server查詢(xún)很久等問(wèn)題,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01