? ? ???關于實時數據庫的優化思路
背景
大概168個換熱站機組,每套機組將近400個點,整體有6萬多個點需要進行實時更新。數據庫里其中有一個監控參數表(yxjk_jkcs),每一個點位屬性都在里面存放,其中有一個字段CS_VALUE 是存放被更新的實時數據。
現象
? ??所有數據更新一次的時間,大概為10分鐘,而達不到2分鐘一更新的實時數據要求的效果。而且數據在更新的過程中,對服務器的資源利用量很大。
分析思路及過程:
一、利用 select * from v$sgainfo;語句查看了系統全局區域
查看了Buffer Cache Size
以及Shared Pool Size ,這兩個一個是負責結果集的緩存大小,一個是負責存儲解析SQL語句
select *from dict where table_name like '%SGA%'—全局緩存
select *from v$version;--數據庫版本情況
select *from v$sgastat WHERE POOL='shared pool' order by bytes desc;
SELECT *FROM V$SGAINFO;
select *from v$sgastat;
select *from v$sga;
select *from v$sga_value;
select *from v$sgastat where pool='shared pool'
selectvalue/1024/1024 from v$parameter where name like '%sga_target%';
?????從語句的返回結果中判斷,緩存區的字節大小為400兆,而32位系統,oracle最大可以支持到1.7G。根據這樣的結果,對緩存區進行了設置,擴大到了1.4G,保證內存的使用空間。
二、利用select * from v$sql查看SQL語句執行的日志
select * from v$sql? wherelower(sql_text) like lower('%yxjk_jkcs%');
然后根據以上的語句得出,語句的執行次數比較多,說明沒有執行預編譯。
??????declare i number;
begin
for i in 1 .. 60000 loop
?update yxjk_jkcs set CS_VALUE='{體驗中換熱站154.tyzx154.scyx_echysx}'where JKD_ID='tyzx154' and CS_ID='scyx_echysx';
end loop;
rollback;
end;
利用oracle本身實驗了一下循環預編譯,發現執行6萬次只用幾秒。同時發現這個表中的參與的兩個查詢條件 JKD_ID和CS_ID是分開的索引。于是把這兩個字段聯合起來建立了一個索引。速度又增快了一些。
三、.net下進行預編譯程序執行
? cmdstr = @"updateyxjk_jkcs set CS_VALUE=:value where JKD_ID=:jkdid and CS_ID=:jkdcs";
??????????????????????????????? OracleCommand cmd = newOracleCommand(cmdstr, conn);
???????????????????????????????cmd.Parameters.Clear();
??????????????????????????????? OracleParameter opvalue = newOracleParameter(":value",OracleType.VarChar, 100);
??????????????????????????????? //opvalue.OracleType = OracleType.VarChar;
??????????????????????????????? //opvalue.ParameterName = "@value";??
??????????????????????????? ????cmd.Parameters.Add(opvalue);
??????????????????????????????? OracleParameter opjkd = newOracleParameter(":jkdid",OracleType.VarChar, 32);
???????????????????????????
???????????????????????????????cmd.Parameters.Add(opjkd);
??????????????????????? ????????OracleParameteropjkcs = new OracleParameter(":jkdcs", OracleType.VarChar,200);
???????????????????????????
???????????????????????????????cmd.Parameters.Add(opjkcs);
?
?
??????????????????????????????? for (int i = 0; i< 60000; i++)
??????????????????????????????? {
???????????????????????????????????cmd.Parameters[":value"].Value= i.ToString();
???????????????????????????????????cmd.Parameters[":jkdid"].Value= "jdyj01^jdyj01";
???????????????????????????????????cmd.Parameters[":jkdcs"].Value= "L_T_two_supply_Y3";
???????????????????????????????????cmd.ExecuteNonQuery();
??????????????????????????????? }
不過在這種情況下,發現交互后,速度仍然不夠理想。
?
?
四、查詢在執行過程中,哪個語句及應用比較慢。
select a.seconds_in_wait, a.* fromv$session_wait a where a.wait_class<>'Idle' order by a.seconds_in_waitdesc--查到的應用慢
查詢到了操作,執行了日志操作,并頻繁的進行的commit操作導致。
select?a.* from v$session a? wherea.sid=138
查到了相應應用的相關信息,就是用傳統的數據提交方式,因為.net下的每一個ExecutNonquery相當于一次語句并一次提交,所以需要變成事務型,多條語句一次提交從而化對應程序的操作方式。
五、減少提交次數,累計事務
?
??OracleConnection myConnection = new OracleConnection(connstr);
??????????????????????? myConnection.Open();
??????????????????????? OracleCommand myCommand= myConnection.CreateCommand();
??????????????????????? OracleTransactionmyTrans;???????????????? ?
???myTrans= myConnection.BeginTransaction(IsolationLevel.ReadCommitted);
??????????????????????? myCommand.Transaction =myTrans;
??cmdstr = @"update yxjk_jkcs set CS_VALUE=:value where JKD_ID=:jkdidand CS_ID=:jkdcs";
??????????????????????????????? myCommand.CommandText= cmdstr;
???????????????????????????????myCommand.Parameters.Clear();
?OracleParameter opvalue = new OracleParameter(":value",OracleType.VarChar, 100);?
???????????????????????????????myCommand.Parameters.Add(opvalue);
OracleParameter opjkd = newOracleParameter(":jkdid", OracleType.VarChar, 32);
myCommand.Parameters.Add(opjkd);
?OracleParameter opjkcs = newOracleParameter(":jkdcs", OracleType.VarChar, 200);
???????????????????????????????myCommand.Parameters.Add(opjkcs);
?
??? ?????????for (int p = 0; p < myllsls.Length;p++)
??????????????????????????????? {
??????????????????????????????????? stringonesql = myllsls[p];
??????????????????????????????????? int fs =onesql.IndexOf(" where JKD_ID=");
???????????????????????????? ???????string jkdidstr = onesql.Substring(fs +14);
??????????????????????????????????? string[]jkdcs = jkdidstr.Split(new string[] { "' and CS_ID='" },StringSplitOptions.RemoveEmptyEntries);
??????????????????????????????????? string jkd= jkdcs[0];
?? ?????????????????????????????????string jkcs =jkdcs[1].ToString().Replace("'\r", "");
???????????????????????????????????myCommand.Parameters[":value"].Value =p.ToString()+"##########";
???????????????????????????????????myCommand.Parameters[":jkdid"].Value =jkd.Replace("'", "");
???????????????????????????????????myCommand.Parameters[":jkdcs"].Value =jkcs.Replace("'", "");
???????????????????????????????????
???????????????????????????????????myCommand.ExecuteNonQuery();
????????????????????????? ??????????
??????????????????????????????????? if (p %5000 == 0)
??????????????????????????????????? {
???????????????????????????????????????myTrans.Commit();
??????????????????????????????????????? myTrans= myConnection.BeginTransaction(IsolationLevel.ReadCommitted);
???????????????????????????????????????Console.WriteLine(p.ToString()+"?"+DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") );
???????????????????????????????????????mydialog.WriteLine(p.ToString() + "?" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
??????????????????????????????????? }
??????????????????????????????? }
以這樣的方式每5000條提交一次,節省了大量的頻繁交互,速度就有了很大的提升。
?
?
?