2016-08-26 2 views
1

우리는 오라클 12c에서 실행되는 매우 큰 데이터베이스 애플리케이션을 관리하기 위해 수년간 flywayDB을 사용하고 있습니다. 이것은 잘 작동하고 매우 신뢰할 수 있습니다.이동 경로 : 많은 수의 스크립트 마이그레이션 성능 저하

하지만 최근에는 데이터베이스 마이그레이션 중에 성능 문제가 발생합니다. 우리의 버전 - 테이블에서 우리가 관리하는 데이터베이스 스케치의 수는 10,000 개를 넘었습니다. 단일 스크립트가 원래 밀리 초에서 현재 약 1 초로 늘어났습니다. 한 번의 마이그레이션 단계마다 이동 경로가 클라이언트 측에서 설치 순위를 계산하기 위해 버전 표의 전체 내용을 선택하는 것 같습니다. 이것은 잘 나르지 않습니다.

플라이 웨이 속도를 높이기위한 가능성이 있습니까? 아니면 버전 표의 내용을 캐싱 할 수 있습니까?

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과 비교하여 약 절반의 시간이 걸렸지 만, 스케일링 문제는 여전히 지속됩니다. 이동 경로는 단일 이주 단계마다 전체 버전 테이블을 선택하므로 버전 테이블이 많은 경우 이주가 크게 지연됩니다.

업데이트 다시

나는 flywayDB 버전 4.0.3의 소스 코드를 살펴본 결과 : org.flywaydb.core.internal.command.DbMigrate#migrate에서 MigrationInfoServiceImpl가 생성되어 새로 고쳐집니다. 그러면 전체 schema_versions-Table이 선택됩니다. 그러나이 단계가 끝나면 단일 마이그레이션 스크립트 만 실행됩니다. 보류중인 모든 스크립트를 대신 마이그레이션 할 것을 기대합니다.

나는 github에서 issue을 열었습니다.

+0

SQL 스크립트가 데이터베이스의 테이블이나 파일 시스템의 파일에 저장되어 있습니까? –

+0

SQL 스크립트는 파일 시스템의 파일입니다. – frifle

+1

프로세스의 각 단계의 성과를 분석 했습니까? 나는 오라클이 눈 깜짝 할 사이에 10000 개의 레코드를 가진 테이블을 읽을 수 있다고 생각한다. 디스크에 10000 개의 파일을 색인하고 읽어야하는 자바 애플리케이션과 OS에 대해서는 그렇게 확신하지 못한다. –

답변

0

issue은 고정되어 있습니다. 오늘 나는 flyway 버전 4.1.2를 테스트했고 성능 문제는 사라졌습니다. boxfuse에서 큰 성과를 가져 주셔서 감사합니다!