昨天遇到一个问题,简单的mark一下,为以后的迁移等工作避坑,情况大概如下:
业务反馈我们的柜面一个登陆功能很慢,需要20s左右才能登陆完成,经过应用开发的排查,发现有一条select视图的语句执行起来非常慢,通过分析发现其执行计划走的非常差,虽然通过hint艰难的将执行计划纠正了一些,但是短时间内无法对应用程序进行整改,且该SQL并没有绑定变量,短时间内执行过不同条件的sql有上百条,通过绑定执行计划也不太现实。最终分析发现是由于其中一张大表的统计信息异常导致sql执行计划走错,该表的统计信息被锁定在5000条,但实际已经有800w数据。
为什么这张表的统计信息会被锁定?我们是否还有其他统计信息被锁定呢?通过以下SQL进行查询:
SELECT
owner,table_name,stattype_locked
FROM DBA_TAB_STATISTICS a
WHERE a.stattype_locked IN ('ALL','DATA','CACHE')
and owner=upper('&table_owner');
发现有近400张表存在统计信息被锁定的情况,而整个库里面该业务用户底下总共也就400多张表,几乎所有表的统计信息均被锁定。
一般我们将执行计划锁定是系统由于下游系统会将normal表用作临时表功能,每天会通过truncate的方式清理表,然后通过sqlldr再统一将数据load进去,此时如果错过统计信息收集时间,则可能导致统计信息错误而走错执行计划。因此,我们会将执行计划清理并锁定,让这些表的统计信息采集动作改为动态采集。
但是很明显,这些表并不是上述用途,那么这些表的统计信息被锁定肯定是不正常的。
通过对一系列官方资料查找,找到了一个类似的mos文档(文档 ID 433240.1),该文档的具体描述如下:
APPLIES TO:
Oracle Database - Enterprise Edition - Version 10.2.0.1 and later
Oracle Database Cloud Schema Service - Version N/A and later
Oracle Database Exadata Express Cloud Service - Version N/A and later
Oracle Database Exadata Cloud Machine - Version N/A and later
Oracle Cloud Infrastructure - Database Service - Version N/A and later
Information in this document applies to any platform.
SYMPTOMS
Either of the following two error messages are signaled:
ORA-38029: object statistics are locked
ORA-20005: object statistics are locked (stattype = ALL)
CAUSE
Possible Cause #1: DBMS_STATS.LOCK_[SCHEMA|TABLE]_STATS has been used to lock statistics on the table.
Possible Cause #2: Using import (imp) or data pump import (impdp) to import a table without data results in the table's statistics being locked in 10gR2.
Oracle� Database Readme
10g Release 2 (10.2)
Part Number B14233-04
39.5Original Export/Import
After an IMPORT is finished for which ROWS=N, the statistics for all tables imported will be locked.
Possible Cause #3: If the table is a queue table then the statistics are intended to be empty and locked so that dynamic sampling will be used due to the table's volatility. During an upgrade to 10gR2 statistics on queue tables are deleted and then locked. In 10gR2 when a queue table is created statistics are locked while still empty.
SOLUTION
If the table is a queue table, then the statistics should remain empty and locked so that dynamic sampling is used due to the volatility of queue tables. If the table is not a queue table, unlock the statistics using
following:
DBMS_STATS.UNLOCK_[SCHEMA|TABLE]_STATS
Or gather statistics on the table using following:
DBMS_STATS.GATHER_[SCHEMA|TABLE|INDEX]_STATS and the force=>true parameter
To prevent import (imp) from locking the table's statistics when importing a table without the rows (rows=n), use statistics=none. To prevent data pump import (impdp) from locking the table's statistics when importing a table without the rows (content=metadata_only), use exclude=(table_statistics,index_statistics).
通过mos描述可以发现,再10.2.0.1及以后版本,如果通过exp/imp或者expdp/impdp只导入metadata的时候,则可能会发生表的统计信息被锁定的情况(但mos中主要说了10g的问题,只能猜测19c中并没有修复这个问题)。
针对本次出现的问题,我们通过以下SQL将统计信息进行解锁,并重新收集统计信息:
DBMS_STATS.UNLOCK_TABLE_STATS(OWNNAME=>'&table_owner',TABNAME=>'&table_name');
DBMS_STATS.GATHER_TABLE_STATS(OWNNAME=>'&table_owner',TABNAME=>'&table_name',DEGREE=>4);
重新收集统计信息后,再次查询,执行计划正确,柜面登陆慢问题顺利解决。
根据mos的解决方案,后续在迁移、导出导入metadata的时候还是要把statistics=none(exp/imp的方式)或者exclude=(table_statistics,index_statistics)(expdp/impdp的方式)加上