创建索引时Liquibase慢度

问题描述

我最近将Java Liquibase版本从3.5.3升级到了3.6.3

我有一个非常繁重的环境,其中有许多数据库和表(我正在使用Oracle)。 在这种环境下,我试图执行一个巨大的变更日志文件,在其中创建表和索引。

在更改日志的一小部分下面查找。

<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.2.xsd">
    
    ...
    ...
    ...

   <changeSet author="me" id="tableCreation78">
        <preConditions onFail="MARK_RAN">
            <not>
                <tableExists  tableName="MY_TABLE_NAME" />
            </not>
        </preConditions>
        <comment>Creating table MY_TABLE_NAME</comment>
        <createTable tableName="MY_TABLE_NAME">
            <column name="M_ID" type="bigint">
                <constraints nullable="false" primaryKey="true" primaryKeyName="PK_MY_TABLE_NAME_190" />
            </column>
            <column name="M_FORMAT" type="int" />
        </createTable>
    </changeSet>

    ...
    ...
    ...

    <changeSet author="me" id="indexCreation121">
        <preConditions onFail="MARK_RAN">
            <tableExists tableName="MY_TABLE_NAME"/>
            <not>
                <indexExists tableName="MY_TABLE_NAME" columnNames="M_FeedER_ID"/>
            </not>
        </preConditions>
        <comment>Creating index for MY_TABLE_NAME</comment>
        <createIndex tableName="MY_TABLE_NAME" indexName="MY_INDEX_NAME">
            <column name="M_ID_INDEX"/>
        </createIndex>
    </changeSet>
    
    ...
    ...
    ...

</databaseChangeLog>

在Liquibase 3.5.3 上,创建索引曾经是快速的。 当我迁移到Liquibase 3.6.3 时,我的性能出现了严重下降。

以前需要1-2分钟才能完成的操作,现在最多需要20分钟即可完成。

变更日志未定义唯一约束。 在调试时,我注意到两个版本之间的众多差异之一。在 3.5.3 中,不会调用listConstraints中的listColumnsUniqueConstraintSnapshotGenerator方法。 在 3.6.3 版本中,即使在更改日志中未定义唯一约束,这些方法也被称为很多方法。我猜想它们来自先前定义的环境表中。

使用完全相同的参数多次调用其中一些查询(请参见下文)。我不知道这是否是 3.6.3 添加的维护步骤。

2020-08-13 17:03:52,270 INFO [main] select ucc.owner as constraint_container,ucc.constraint_name as constraint_name,ucc.column_name,f.validated as constraint_validate from all_cons_columns ucc INNER JOIN all_constraints f ON ucc.owner = f.owner AND ucc.constraint_name = f.constraint_name where ucc.constraint_name='UC' and ucc.owner='DB' and ucc.table_name not like 'BIN$%' order by ucc.position

我不确定这是否是导致回归的原因,但老实说,我没有想法。 有人知道这是否可能是导致回归的原因吗? 他们是否在Liquibase 3.6.3 添加了新的维护步骤,可能会导致性能大幅下降?

非常感谢您!

解决方法

您可能需要对Oracle数据字典执行维护。与普通的Oracle数据库相比,使用Liquibase的数据库往往会丢弃和创建更多的对象,这可能会导致元数据查询的性能问题。

首先,收集针对固定对象(V $对象)和数据字典(ALL_对象)的优化器统计信息。这些信息有助于Oracle为元数据查询建立良好的执行计划。下面的语句将花费几分钟,但可能只需要每年运行一次:

begin
    dbms_stats.gather_fixed_objects_stats;
    dbms_stats.gather_dictionary_stats;
end;
/

数据字典查询问题的另一个常见原因是回收站中有大量对象。回收站在生产系统上非常有用,它使您可以立即从放错表中恢复。但是在开发环境中,如果不断删除但不清除数千个对象,则这些旧对象会减慢某些元数据查询的速度。

--Count the number of objects in the recycle bin.
select count(*) from dba_recyclebin;
--Purge all of them if you don't need them. Must be run as SYS.
purge dba_recyclebin;

对于某些数据字典问题,这是两个快速而轻松的解决方案。如果这样做没有帮助,则可能需要调整特定的SQL语句,这可能需要大量信息。例如-您的系统针对ALL_CONS_COLUMNS运行该查询需要多长时间? (在我的数据库上,它的运行时间不到一秒钟。)

运行Liquibase,然后使用以下查询来查找最慢的元数据查询:

select elapsed_time/1000000 seconds,executions,sql_id,sql_fulltext,gv$sql.*
from gv$sql
order by elapsed_time desc;