在一台ORACLE服務器上做巡檢時,使用下面SQL找出DISK_READ最高的TOP SQL分析時,分析過程中,有一條SQL語句的一些反常現象,讓人覺得很奇怪:
SELECT SQL_ID,
SQL_TEXT,
DISK_READS,
BUFFER_GETS,
PARSING_SCHEMA_NAME,
EXECUTIONS
FROM V$SQLAREA
ORDER BY DISK_READS DESC;
在SQL Developer中查看SQL的預估執行計划,發現執行計划走INDEX UNIQUE SCAN,而且IO COST其實不高。如下所示,而且執行次數也不是非常多,那么推斷:很有可能這個SQL的實際執行計划跟預估的執行計划有很大偏差。
SELECT
"Extent1"."SC_NO" AS "SC_NO",
"Extent1"."CUSTOMER_CD" AS "CUSTOMER_CD",
"Extent1"."FACTORY_CD" AS "FACTORY_CD",
"Extent1"."REQ_USER_ID" AS "REQ_USER_ID",
"Extent1"."REQ_USER_GRP_ID" AS "REQ_USER_GRP_ID"
FROM "SC_HD" "Extent1"
WHERE ("Extent1"."SC_NO" = :p__linq__0) AND (ROWNUM <= (1) )
於是根據SQL_ID生成了對應SQL的awrsqrpt報表,如下截圖所示,實際執行計划確實是全表掃描,Buffer Gets與Disk Reads也很高
在sqltrpt.sql里面分析查看該SQL時,如下所示, 可以發現其綁定變量存在隱式轉換(implicit data type conversion),導致執行計划走全表掃描
於是分析了一下綁定變量的類型,發現:P__LINQ__0的類型為NVARCHAR(32) 而實際上字段SC_NO為VARCHAR(16),所以肯定是應用程序里面給該綁定變量賦值出現了問題。
SQL> COL NAME FOR A32;
SQL> COL DATATYPE_STRING FOR A20;
SQL> COL VALUE_STRING FOR A20;
SQL> SELECT NAME, DATATYPE_STRING, VALUE_STRING
2 FROM v$sql_bind_capture
3 WHERE SQL_ID='&SQL_ID' ;
Enter value for sql_id: dhg6qnxv9c4nz
old 3: WHERE SQL_ID='&SQL_ID'
new 3: WHERE SQL_ID='dhg6qnxv9c4nz'
NAME DATATYPE_STRING VALUE_STRING
-------------------------------- -------------------- --------------------
:P__LINQ__0 NARCHAR2(32) GS17K16005
SQL>
后面開發人員協助檢查發現,因為這個SQL是代碼中Lambda表達式自動生成,后面在Property中設置了字段類型以及長度,問題解決。
//表SC_HD
modelBuilder.Entity<SC_HD>().ToTable("SC_HD", OracleSchema);
modelBuilder.Entity<SC_HD>().HasKey(x => x.SC_NO);