我们使用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。