ORACLE綁定變數隱式轉換導致性能問題

来源:http://www.cnblogs.com/kerrycode/archive/2016/03/15/5278872.html
-Advertisement-
Play Games

年後一次系統升級後,監控資料庫的工具DPA發現資料庫的Total Wait時間突然飆增,如下截圖所示,資料庫的總體等待時間對比升級前飆增了非常多 另外就是發現出現了較多的等待事件,主要有latch: cache buffers chains、 latch: shared pool 、db file ...


    年後一次系統升級後,監控資料庫的工具DPA發現資料庫的Total Wait時間突然飆增,如下截圖所示,資料庫的總體等待時間對比升級前飆增了非常多

clip_image001

另外就是發現出現了較多的等待事件,主要有latch: cache buffers chains、 latch: shared pool 、db file scattered read。根據這邊的監控發現TOP SQL裡面從升級前的0次變為了一天的一萬多次(有些甚至更多),分析過後我們就找開發人員瞭解一下系統升級變跟的內容和改動

開發人員堅定的告訴們介紹,他只是將他負責的那個模塊裡面那些拼接SQL(Literal SQL)語句改寫成了綁定變數(因為我們系統大量使用拼接SQL的方式,硬解析非常嚴重),所以我們一直建議他們使用綁定變數。由於改為綁定變數,所以DPA以前沒有捕獲這些SQl,後面因為執行次數激增,所以捕獲了這些SQL,也發現其執行次數明顯變化了,例如有些SQL語句的執行次數上萬了。

後面經過分析、跟蹤過後發現修改為綁定變數的SQL的實際執行計劃變成全表掃描了。這也能解釋為什麼db file scattered read等待事件出現,因為全表掃描的緣故。下麵就其中的一個SQL語句做分析,如下所示,我們在Toad或SQL Developer工具裡面查看預估執行計劃時,其執行計劃都是走索引掃描(Index Scan),但是實際執行計劃就是走全表掃描

clip_image002

 

 

實際執行計劃(截圖來自WORKLOAD REPOSITORY SQL Report )

clip_image003

剛開始我們以為是綁定變數的窺探機製造成(使用SQL首次運行時的值來生成執行計劃。後續再次運行該SQL語句則使用首次執行計劃來執行),但是分析過後發現,SC_NO這個欄位建有唯一索引,不存在所謂的數據傾斜的情況。非常的糾結,納悶,不解。同事用10046跟蹤了SQL語句(其實是跟蹤某個自己在Toad裡面執行的SQL語句,這也是問題一直沒有發現的原因),想不明白為什麼,隱隱懷疑是資料庫的bug來著,直到後面我在sqltrpt.sql查看某些SQL的調優優化建議,突然看到下麵信息:

3- Restructure SQL finding (see plan 1 in explain plans section)

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

The predicate SYS_OP_C2C("SC_NO")=:B1 used at line ID 5 of the execution plan contains an implicit data type conversion on indexed column "SC_NO".This implicit data type conversion prevents the optimizer from selecting indices on table "SC_HD".

Recommendation

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

- Rewrite the predicate into an equivalent form to take advantage of indices.

 

頓時豁然開朗,肯定是開發人員在使用綁定變數時,使用了不一致的數據類型,導致了隱式轉換(implicit data type conversion),於是聯繫開發人員確認,要了程式裡面的代碼,果然如此,SC_NO的數據類型為VARCHAR2,但是在代碼裡面綁定變數的類型為OracleType.NVarChar。悲劇的是幾乎所有綁定變數都由於開發人員疏忽,都給錯了數據類型。所以出現這麼嚴重的情況

...........................................................
param = new OracleParameter(":scNo", OracleType.NVarChar);
            param.Value = Server.UrlDecode(joNo).ToUpper();
            paramsList.Add(param);
...........................................................

 

那麼我們下麵我們模擬一下綁定變數數據類型不一致,出現隱式轉換導致不走索引的情況

SQL> alter system flush shared_pool;
 
System altered.
 
SQL> set autotrace on;
SQL> variable sc_no nvarchar2(20);
SQL> exec :sc_no :='A01Adfddf01I';
 
PL/SQL procedure successfully completed.
 
SQL> select  count(1) from sc_hd 
  2  where sc_no =:sc_no 
  3    and jo_status<>'l2' 
  4    and status<>'x';
 
  COUNT(1)
----------
         0
 
 
Execution Plan
----------------------------------------------------------
Plan hash value: 326413811
 
----------------------------------------------------------------------------------------
| Id  | Operation                    | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |         |     1 |    16 |     3   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE              |         |     1 |    16 |            |          |
|*  2 |   TABLE ACCESS BY INDEX ROWID| SC_HD   |     1 |    16 |     3   (0)| 00:00:01 |
|*  3 |    INDEX UNIQUE SCAN         | SC_HEAD |     1 |       |     2   (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter("JO_STATUS"<>'l2' AND "STATUS"<>'x')
   3 - access("SC_NO"=:SC_NO)
 
 
Statistics
----------------------------------------------------------
       2082  recursive calls
          6  db block gets
     109260  consistent gets
     108647  physical reads
          0  redo size
        514  bytes sent via SQL*Net to client
        492  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
         48  sorts (memory)
          0  sorts (disk)
          1  rows processed
 
SQL> 

clip_image004

 

 

此時,你查看實際執行計劃,就會發現其走全表掃描。如下所示

clip_image005

clip_image006

 

如果此時你用一模一樣的SQL(空格,字元大小一致,如下所示),在TOAD裡面執行,即使你給綁定變數賦予的是VARCHAR2類型的數據,也會發現其實際執行計划走全表掃描,這個是因為綁定變數窺探,使用SQL首次運行時的值來生成執行計劃。後續再次運行該SQL語句則使用首次執行計劃來執行的緣故

select  count(1) from sc_hd 
where sc_no =:sc_no 
  and jo_status<>'l2' 
  and status<>'x';

 

如果空格不一致,或大小寫,或換行不一致,你又會發現其實際執行計划走索引了,這也是當初我們在不瞭解應用程式源代碼的情況,被這個情況給折騰瘋了的情況,以為是資料庫的bug引起的。其實還是因為綁定變數的數據類型與實際欄位的數據類型不一致而引起的。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  •        大數據時代的到來意味著數據量的爆炸,也意味著收集數據的難度將大幅增加。為了將海量的數據收集起來,埋點技術應運而生。然而隨著大數據的發展和深入,用戶的要求越來越高,埋點技術開始變得力不從心。        近期,一些公司開始以“無埋點技術”為賣點,開始到處宣傳無埋點比埋點好,那麼到底事實
  •  
  •   -- Create Customers table-- CREATE TABLE Customers( cust_id char(10) NOT NULL , cust_name char(50) NOT NULL , cust_address char(50) NULL , cust_c
  • 所使用的資料庫資料在:資料庫資料   第三課:排序檢索數據 3.1 排序數據 按單列排序 如果不排序,數據一般將以它在底層表中出現的順序顯示,這有可能是數據最初添加到表中的順序。但是,如果數據隨後進行過更新或刪除,那麼順尋將不再是當初的順序; ORDER BY 取一個或多個列的名字,併進行順序輸出
  • 如果你資料庫是通過sqlserver 2008以上版本創建的請繞過: 客戶以前用的是sqlserver2005 創建的資料庫。後來升級到 sqlserver 2008 . 有個業務用到了json查詢 .可搜索了一下發現 sqlserver(sqlserver2016除外) 不支持json查詢. 在網
  •  
  • 一、 Oracle 下載   官方下地址   註意Oracle分成兩個文件,下載完後,將兩個文件解壓到同一目錄下即可。 路徑名稱中,最好不要出現中文,也不要出現空格等不規則字元。   二、Oracle安裝   1. 解壓縮文件,將兩個壓縮包一起選擇, 滑鼠右擊 ->  解壓文件。   2. 兩者解壓
  • oracle表的管理
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...