Flyway:迁移大量脚本的性能降低

时间:2016-08-26 13:26:29

标签: java oracle flyway

我们使用flywayDB多年来管理在oracle 12c上运行的相当大的数据库应用程序。这很好,非常可靠。

但是最近我们在数据库迁移期间遇到了性能问题。我们在版本表中管理的数据库skripts数量已超过10,000。用于迁移单个脚本的飞行时间从最初的几毫秒增加到当前大约一秒。似乎每个迁移步骤的flyway选择版本表的完整内容,以在客户端计算其安装等级。这不能很好地扩展。

是否有可能加速飞路,可能是通过缓存版本表的内容?

我们正在使用flyway版本3.2.1的Java-API。

为了完整起见,我编写了一个测试用例来证明这种行为。

@RunWith(Parameterized.class)
public class PerformanceTestcase {

private static Logger LOG = Logger.getLogger( PerformanceTestcase.class.getName() );

@Parameter
public int noOfScripts;

@Before
public void generateLotsOfInstallerSkripts() throws IOException {
    LOG.log(Level.INFO, "generating {0} skripts", noOfScripts);
    Path baseVersion = getBaseVersionPath();
    generateSkripts( noOfScripts, baseVersion, BASE_SKRIPT_NAME );
}

@Test
public void testPerformance() throws IOException, SQLException {
    // this one does not scale well with increasing noOfScripts
    migrate();
}

private static final String SCHEMA_TABLE_NAME = "test_versions";

private static final String SKRIPT_NAME_FORMAT = "%s.%05d__test.sql";
private static final String SKRIPT_CONTENT = "select %05d from dual;";

private static final String FILESYSTEM = "filesystem:";

private static final String BASE_SKRIPT_NAME = "V00.00.00";
private static final String BASE_DIR = "/tmp/performanceTest";

private void migrate() throws SQLException {
    Flyway flyway = new Flyway();
    flyway.setDataSource( getDataSource() );
    flyway.setLocations( FILESYSTEM + BASE_DIR );
    flyway.setTable( SCHEMA_TABLE_NAME );
    flyway.setBaselineVersionAsString(BASE_SKRIPT_NAME.substring(1) );
    flyway.setBaselineOnMigrate(true);
    flyway.setValidateOnMigrate(false);

    flyway.migrate();
}

@Parameters(name="noOfScripts={0}")
public static Iterable<? extends Object> data() {
    List<Integer> retval = new LinkedList<Integer>();
    for ( int i=0; i<16000; i+=1000 ) {
        if ( i>0 ) retval.add( Integer.valueOf(i) );
        retval.add( Integer.valueOf(i+100) );
    }
    return retval;
}

private Path getBaseDirPath() throws IOException {
    Path base = Paths.get(BASE_DIR);
    if ( !Files.exists(base) ) {
        Files.createDirectory(base);
    }
    return base;
}

private Path getBaseVersionPath() throws IOException {
    Path base = getBaseDirPath();
    Path baseVersion = base.resolve(BASE_SKRIPT_NAME);
    if ( !Files.exists(baseVersion) ) {
        Files.createDirectories(baseVersion);
    }
    return baseVersion;
}

private void generateSkripts( int numberOfSkripts, Path baseDir, String baseName ) throws IOException {
    for (int i = 0; i < numberOfSkripts; i++) {
        Path file = baseDir.resolve( String.format(SKRIPT_NAME_FORMAT, baseName, i) );
        Files.write( file
                   , Arrays.asList( new String[] { String.format( SKRIPT_CONTENT, i ) } )
                   , StandardOpenOption.CREATE
                   , StandardOpenOption.TRUNCATE_EXISTING
                   );
    }

}

private DataSource getDataSource() throws SQLException {
    OracleDataSource ds = new OracleDataSource();
    ds.setURL(CONNECTION_URL);
    return ds;
}
}

更新

我只使用flywayDB的当前版本4.0.3运行测试用例。与3.2.1相比,它运行的时间大约是一半,但是缩放问题仍然存在。 Flyway正在为每个迁移步骤选择完整版本表,这会在版本表填充完全时显着减慢迁移速度。

再次更新

我已查看了flywayDB版本4.0.3的源代码:在org.flywaydb.core.internal.command.DbMigrate#migrate中创建并刷新了MigrationInfoServiceImpl。这将选择完整的schema_versions-Table。但在该步骤之后,只执行一个迁移脚本。我希望改为迁移所有挂起的脚本。

我已经在github上打开了issue

1 个答案:

答案 0 :(得分:0)

issue已修复。今天我测试了飞路版4.1.2,性能问题已经消失。感谢boxfuse的精彩工作!