国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 數據庫 > Oracle > 正文

檢查Oracle數據庫中不合理的sql語句

2024-08-29 13:37:38
字體:
來源:轉載
供稿:網友

  代碼:
  select sql_text ,sharable_mem from v$sql where sharable_mem > '100000' order by sharable_mem ; 
  
  
  上面的sql語句是查詢shared pool中占用內存超過100K的sql語句。
  
  這個sql可以非常有效的檢查出Oracle shared pool中那些嚴重占用內存的sql,根據我的經驗,絕大多數有問題的sql語句都會在這里留下痕跡,通過在這里找出有問題的sql語句并進行修改,再反復運行這個sql腳本,直到所以有問題的sql都處理完畢,這就是對Oracle數據庫在sql上面的最好的優化,可以保證不會因為程序員的sql語句問題導致Oracle數據庫的性能問題。
  
  共享池主要由庫緩沖區(共享SQL區和PL/SQL區)和數據字典緩沖區組成。具體的情況你隨便找一本介紹Oracle內存結構的書上面都有講到。我就不把書上的內容給你打印一遍了,自己去看。
  
  select * from v$sgastat; --顯式SGA的狀態信息。
  
  有的人寫的SQL語句非常復雜,嵌套了好幾層,SQL語句本身寫的很差,就有可能會占用很大的SQL區域。
  
  其實現實的很多情況是本來不需要那么復雜的sql的時候,由于程序員水平不夠,寫了那種很糟糕很復雜的sql,造成的數據庫性能問題。
  
  另外還有一個常識問題,卻很輕易被忽略。比如:
  
  代碼:
  select * from table_name where id = 1;
  select * from table_name where id = 2; 
  對于這種帶參數的sql,id = ? 這個地方叫做站位符(Placeholder)。
  
  拿php為例,很多人喜歡這樣寫代碼
  
  代碼:
  $sql = "select * from table_name where id = ";
  $id=1;
  $stmt = ociparse($conn,$sql.$id);
  ociexecute($stmt);
  ......
  $id = 2;
  $stmt = ociparse($conn,$sql.$id);
  ociexecute($stmt); 
  
  拿java為例,是這樣的:
  代碼:
  String sql = "select * from table_name where id = ";
  Statement stmt = conn.createStatement();
  
  rset = stmt.executeQuery(sql+"1");
  ......
  rset = stmt.executeQuery(sql+"2"); 
  
  
  這種寫法,對于Oracle數據庫來說,完全就是兩條不同的sql語句,
  代碼:
  select * from table_name where id = 1;
  select * from table_name where id = 2; 
  每次查詢都要進行sql語句的執行解析,并且每個sql都會分配一個區域來存放sql解析后的二進制可執行代碼。試想,要是id不同的10萬個sql呢?Oracle就會分配10萬個sql區域來分別存放10萬個這樣的id不同的sql語句。對于一個數據庫驅動的Web網站這樣情況下,SGA開的再大,也會很快被耗盡share pool的,最后報一個ORA-4031錯誤。數據庫就連接不上了,只好重起。
  
  正確的寫法應該是:
  
  代碼:
  $stmt = ociparse($conn,"select * from table_name where id = :id");
  ocibindbyname($stmt,":id",&$id, 12);
  
  $id =1;
  ociexecute($stmt);
  ...
  $id = 2;
  ociexecute($stmt); 
  
  
  代碼:
  PReparedStatement pstmt = conn.prepareStatement("select * from table_name where id = ?");
  
  pstmt.setInt(1,1);
  rset = pstmt.executeQuery();
  ...
  pstmt.setInt(1,2);
  rset = pstmt.executeQuery(); 
  
  這樣Oracle數據庫就知道你實際上用的都是同一條sql語句,會以這樣的形式:
  select * from table_name where id = :1
  解析執行后存放在sql區域里面,當以后再有一樣的sql的時候,把參數替換一下,就馬上執行,不需要再解析sql了。
既加快了sql執行速度,也不會占有過多SGA的share pool。
  
  可惜的是,很多程序員明知道這個問題,卻意識不到問題的嚴重性,因為上面那種寫法,編程的時候很靈活,sql語句可以動態構造,實現起來很輕易,后面那種寫法,sql語句是寫死的,參數不能再變了,編程經常會非常麻煩。
  
  很多數據庫的性能問題都是這樣造成的。
  
  有愛好在一個生產系統中,用上面sql檢查一下,看看是否選擇出來的是否l有很多都是一樣的sql語句,只是參數不同,假如是這樣的話,就說明程序員的代碼寫的有問題。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 伊通| 长治县| 尼勒克县| 开封市| 留坝县| 政和县| 安吉县| 台东市| 武乡县| 嘉义县| 斗六市| 石屏县| 乐都县| 玛纳斯县| 绥芬河市| 舟山市| 河津市| 高雄县| 湘潭市| 双流县| 辉县市| 宣化县| 宾川县| 合肥市| 台山市| 英山县| 壶关县| 广昌县| 达州市| 合肥市| 七台河市| 神农架林区| 宜宾县| 达尔| 桂平市| 蒙山县| 庄河市| 青神县| 康马县| 平湖市| 虎林市|