這個是老生產談的事情,統計信息不準確導致sql執行異常,此次記錄的主要是表的統計信息被鎖住導致無法正常收集統計信息導致sql執行異常:
收集表的統計信息:
SQL> exec DBMS_STATS.GATHER_TABLE_STATS(OWNNAME => 'crmdb', TABNAME => 'T_ORDER_DELIVERY', CASCADE => TRUE);
BEGIN DBMS_STATS.GATHER_TABLE_STATS(OWNNAME => 'crmdb', TABNAME => 'T_ORDER_DELIVERY', CASCADE => TRUE); END;
*
ERROR at line 1:
ORA-20005: object statistics are locked (stattype = ALL)
ORA-06512: at "SYS.DBMS_STATS", line 24281
ORA-06512: at "SYS.DBMS_STATS", line 24332
ORA-06512: at line 1
確認出錯信息:
SQL> select table_name,d.stattype_locked,D.LAST_ANALYZED,d.NUM_ROWS from user_tab_statistics d where table_name in ('T_ORDER_DELIVERY');
TABLE_NAME STATTYPE_LOCKED LAST_ANALYZED NUM_ROWS
T_ORDER_DELIVERY ALL 27-APR-2017 22:00:12 0
SQL> select count(*) from T_ORDER_DELIVERY;
COUNT(*)
1029883
說明該表的統計信息不準確,且自2017年以來都沒有收集過;
解決方案:
1)解鎖單個表對象:
查出schema下所有被鎖定的表:
select table_name from user_tab_statistics where stattype_locked is not null;
查詢單個表:
SELECT TABLE_NAME,D.STATTYPE_LOCKED,D.LAST_ANALYZED,D.NUM_ROWS FROM USER_TAB_STATISTICS D WHERE TABLE_NAME IN ('T_ORDER_DELIVERY');
然後解鎖對象:
exec dbms_stats.unlock_table_stats('username','table_name');
SQL> exec dbms_stats.unlock_table_stats('crmdb','T_ORDER_DELIVERY');
PL/SQL procedure successfully completed.
再次收集統計信息:
SQL> exec DBMS_STATS.GATHER_TABLE_STATS(OWNNAME => 'crmdb', TABNAME => 'T_ORDER_DELIVERY', CASCADE => TRUE);
PL/SQL procedure successfully completed.
SQL> select table_name,d.stattype_locked,D.LAST_ANALYZED,d.NUM_ROWS from user_tab_statistics d where table_name in ('T_ORDER_DELIVERY');
TABLE_NAME STATTYPE_LOCKED LAST_ANALYZED NUM_ROWS
T_DM_ORDER_DELIVERY 22-JAN-2019 11:07:05 1029884
解鎖整個schema:
DBMS_STATS.UNLOCK_SCHEMA_STATS('username');
那麼爲什麼這些表的統計信息會被鎖定呢?
有可能是爲了穩定執行計劃,或者是impdp只導入metadata_only導致,或者是人爲手動鎖定等。正常在Oracle10g及以上,Oracle默認會根據需要自動收集統計信息,如果想要想手動鎖住統計信息,
可以使用DBMS_STATS.LOCK_SCHEMA_STATS和DBMS_STATS.LOCK_TABLE_STATS包進行鎖定。