Como projetar a solução de importação e exportação para milhões de dados?

  • perspectiva

  • 1 Comparação das vantagens e desvantagens das versões POI tradicionais

  • 2 Qual forma de usar depende da situação

  • 3 milhões de importação e exportação de dados (prato)

  • 4 Resumo


perspectiva

No desenvolvimento de projetos, muitas vezes é necessário usar importação e exportação de dados. Importar é importar do Excel para o banco de dados e exportar é consultar os dados do banco de dados e, em seguida, usar o POI para gravar no Excel.

O pano de fundo para escrever este artigo é porque encontrei a importação e exportação de big data no trabalho. Já que o problema surgiu, é melhor fugir e matá-lo! ! !

Desde que seja resolvido desta vez, será fácil resolver o mesmo problema mais tarde.

Sem mais delongas, vamos começar a se masturbar! ! !

1 Comparação das vantagens e desvantagens das versões POI tradicionais

De fato, ao pensar em importar e exportar dados, é natural pensar na tecnologia poi do apache e nos problemas de versão do Excel.

Como precisamos importar e exportar, vamos dar uma olhada na versão da tecnologia poi tradicional e comparar suas vantagens e desvantagens primeiro!

Em primeiro lugar, sabemos que a interface que mais conhecemos no POI é uma interface do tipo WorkBook. Nossa versão do POI também é atualizada e as classes de implementação dessas portas são atualizadas ao mesmo tempo:

  • Manual de HSSF:

Essa classe de implementação é o objeto que mais usamos no início e pode operar todas as versões do Excel anteriores ao Excel2003 (incluindo 2003). Antes de 2003, o sufixo da versão do Excel ainda era .xls

  • Manual do XSSF:

Esta classe de implementação pode ser encontrada em muitas empresas e ainda está em uso. É a versão entre Excel2003--Excel2007. A extensão do Excel é .xlsx

  • Manual do SXSSF:

Esta classe de implementação está disponível apenas nas versões posteriores ao POI3.8, pode operar todas as versões do Excel posteriores ao Excel2007 e a extensão é .xlsx

Depois de saber aproximadamente que usaremos essas três classes de implementação e as versões e sufixos do Excel que elas podem operar nas operações de importação e exportação, vamos analisá-las em suas vantagens e desvantagens

HSSF Workbook

No entanto, é a forma mais comum na versão POI:

  • Sua desvantagem é que só pode exportar até 65535 linhas, ou seja, a função de dados exportados reportará um erro caso ultrapasse esses dados;

  • Sua vantagem é que ele não reportará estouro de memória. (Como a quantidade de dados é inferior a 7w, a memória geralmente é suficiente. Em primeiro lugar, você deve saber claramente que este método é ler os dados na memória primeiro e depois operá-los)

Pasta de Trabalho XSSF

  • Vantagens: A aparência deste formulário é romper HSSFWorkbooka limitação de 65535 linhas, para as 1.048.576 linhas e 16.384 colunas da versão Excel2007, podendo exportar até 104w de dados;

  • Desvantagens: Surgiu o problema associado: embora o número de linhas de dados exportados tenha aumentado muitas vezes, o problema de estouro de memória subsequente também se tornou um pesadelo. Como o livro, planilha, linha, célula etc. que você criou são todos armazenados na memória antes de serem gravados no Excel (isso sem contar alguns estilos e formatos do Excel etc.), é concebível que, se a memória não estourar , o É um pouco anticientífico! ! !

SXSSF Workbook

A partir da versão 3.8 do POI, é fornecido um método SXSSF com pouca memória ocupada baseado em XSSF:

vantagem:

  • Este método geralmente não causa estouro de memória (ele usa o disco rígido em troca de espaço de memória,

  • Ou seja, quando os dados na memória atingem um determinado nível, os dados serão persistidos no disco rígido para armazenamento e todos os dados armazenados na memória são os dados mais recentes).

  • E suporta a criação de grandes arquivos do Excel (mais de um milhão de dados são mais do que suficientes).

deficiência:

  • Como parte dos dados persiste no disco rígido e não pode ser visualizada e acessada, isso levará a,

  • Ao mesmo tempo, podemos acessar apenas uma certa quantidade de dados, ou seja, os dados armazenados na memória;

  • sheet.clone()O método não terá mais suporte ou devido à persistência;

  • A avaliação de fórmulas não é mais suportada ou, devido à persistência, os dados no disco rígido não podem ser lidos na memória para cálculo;

  • Ao usar o método de modelo para baixar dados, o cabeçalho da tabela não pode ser alterado ou, devido ao problema de persistência, não pode ser alterado após a gravação no disco rígido;

2 Qual forma de usar depende da situação

Depois de entender e conhecer as vantagens e desvantagens dessas três pastas de trabalho, qual método usar depende da situação:

Eu geralmente faço escolhas de análise com base nas seguintes situações:

1. Quando os dados que frequentemente importamos e exportamos não excedem 7w, eles podem ser usados  HSSFWorkbook ​​ou  XSSFWorkbookambos;

2. Recomenda-se usar quando a quantidade de dados for superior a 7w e o Excel exportado não envolver operações nos estilos, fórmulas e formatos do Excel SXSSFWorkbook;

3. Quando a quantidade de dados excede 7w e precisamos operar os cabeçalhos de tabela, estilos, fórmulas, etc. no Excel, neste momento, podemos usar o  XSSFWorkbook método de cooperação para consultar em lotes e gravar no Excel em lotes;

3 milhões de importação e exportação de dados (prato)

Eu fiz muitos prenúncios, então agora falarei sobre as soluções de importação e exportação de mais de um milhão de dados que encontrei em meu trabalho:

Para resolver um problema, devemos primeiro entender qual é o problema?

1. A quantidade de dados que encontrei é extremamente grande. Usar o método POI tradicional para concluir a importação e exportação obviamente causará um estouro de memória e a eficiência será muito baixa;

2. select * from tableNameDefinitivamente não é possível usar uma grande quantidade de dados diretamente, e definitivamente será muito lento descobrir 3 milhões de dados de uma só vez;

3. Quando os dados de 300w forem exportados para o Excel, não devem ser escritos em uma única planilha, então a eficiência será muito baixa, estima-se que demore alguns minutos para abrir;

4. Os dados de 300w exportados para Excel não devem ser exportados para Excel linha por linha. Operações frequentes de IO são absolutamente inaceitáveis;

5. Ao importar, 3 milhões de dados são armazenados no banco de dados, e definitivamente não funcionará se você inserir um a um em um loop;

6. Ao importar dados de 300w, se você usar a inserção de lote do Mybatis, definitivamente não funcionará, porque a inserção de lote do Mybatis é na verdade um ciclo SQL; também é muito lento.

Soluções:

Por 1:

Na verdade, o problema é o estouro de memória. Precisamos apenas usar o método do POI apresentado acima. O principal problema é que o POI original é bastante problemático de resolver.

Depois de consultar as informações, encontrei uma ferramenta de empacotamento POI EasyExcel da Ali, e os problemas acima serão resolvidos;

Para 2:

Não podemos consultar todos os dados de uma vez, podemos consultar em lotes, mas é só uma questão de consultar várias vezes, e existem muitos plug-ins de paginação no mercado. Este problema é fácil de resolver.

Para 3:

Você pode gravar 3 milhões de dados em planilhas diferentes e apenas um milhão de dados podem ser gravados em cada planilha.

Para 4:

Não é possível gravar no Excel linha por linha, podemos gravar os dados consultados em lotes no Excel em lotes.

Para 5:

Ao importar para o banco de dados, podemos armazenar os dados lidos no Excel em uma coleção e, quando atingir um determinado valor, inseri-lo diretamente no banco de dados em lotes.

Para 6:

Não podemos usar a inserção em lote do Mybatis, podemos usar a inserção em lote do JDBC para cooperar com transações para concluir a inserção em lote no banco de dados. Ou seja, o Excel lê em lotes + inserções JDBC em lotes + transações.

3.1 Introdução ao EasyExcel

Anexe o endereço do GitHub: https://github.com/alibaba/easyexcel

Os tutoriais e instruções no endereço do GitHub são bem detalhados, e existem códigos de demonstração para leitura e escrita, então não vou entrar em detalhes sobre sua introdução aqui.

Quanto a como a camada inferior do EasyExcel realiza isso, ainda precisa ser estudado.

3.2 Exportação de dados de 300 W

EasyExcel completa a exportação de dados de 300w. A dificuldade técnica já é conhecida e o próximo passo é fornecer sua própria solução para essa dificuldade.

Soluções de exportação de dados de 300 W:

  • Em primeiro lugar, no nível do banco de dados de consulta, você precisa consultar em lotes (eu uso 20w por consulta)

  • Use a ferramenta EasyExcel para escrever os dados uma vez a cada finalização da consulta;

  • Quando uma Planilha estiver preenchida com 100w de dados, comece a gravar os dados consultados em outra Planilha;

  • Isso faz um loop até que todos os dados sejam exportados para o Excel.

Perceber:

1. Precisamos calcular o número de Folhas e o número de gravações de loop. Especialmente os tempos de gravação da última planilha

Como você não sabe quantos dados foram gravados na última seleção de planilha, pode ser 100w ou 25w, porque os 300w aqui são apenas dados simulados e os dados exportados podem ser mais ou menos que 300w

2. Precisamos contar o número de gravações, porque usamos consultas de paginação, então precisamos prestar atenção ao número de gravações.

Na verdade, quantas vezes você consulta o banco de dados é quantas vezes você escreve

//导出逻辑代码
public void dataExport300w(HttpServletResponse response) {
    {
        OutputStream outputStream = null;
        try {
            long startTime = System.currentTimeMillis();
            System.out.println("导出开始时间:" + startTime);

            outputStream = response.getOutputStream();
            ExcelWriter writer = new ExcelWriter(outputStream, ExcelTypeEnum.XLSX);
            String fileName = new String(("excel100w").getBytes(), "UTF-8");

            //title
            Table table = new Table(1);
            List<List<String>> titles = new ArrayList<List<String>>();
            titles.add(Arrays.asList("onlineseqid"));
            titles.add(Arrays.asList("businessid"));
            titles.add(Arrays.asList("becifno"));
            titles.add(Arrays.asList("ivisresult"));
            titles.add(Arrays.asList("createdby"));
            titles.add(Arrays.asList("createddate"));
            titles.add(Arrays.asList("updateby"));
            titles.add(Arrays.asList("updateddate"));
            titles.add(Arrays.asList("risklevel"));
            table.setHead(titles);

            //模拟统计查询的数据数量这里模拟100w
            int count = 3000001;
            //记录总数:实际中需要根据查询条件进行统计即可
            Integer totalCount = actResultLogMapper.findActResultLogByCondations(count);
            //每一个Sheet存放100w条数据
            Integer sheetDataRows = ExcelConstants.PER_SHEET_ROW_COUNT;
            //每次写入的数据量20w
            Integer writeDataRows = ExcelConstants.PER_WRITE_ROW_COUNT;
            //计算需要的Sheet数量
            Integer sheetNum = totalCount % sheetDataRows == 0 ? (totalCount / sheetDataRows) : (totalCount / sheetDataRows + 1);
            //计算一般情况下每一个Sheet需要写入的次数(一般情况不包含最后一个sheet,因为最后一个sheet不确定会写入多少条数据)
            Integer oneSheetWriteCount = sheetDataRows / writeDataRows;
            //计算最后一个sheet需要写入的次数
            Integer lastSheetWriteCount = totalCount % sheetDataRows == 0 ? oneSheetWriteCount : (totalCount % sheetDataRows % writeDataRows == 0 ? (totalCount / sheetDataRows / writeDataRows) : (totalCount / sheetDataRows / writeDataRows + 1));

            //开始分批查询分次写入
            //注意这次的循环就需要进行嵌套循环了,外层循环是Sheet数目,内层循环是写入次数
            List<List<String>> dataList = new ArrayList<>();
            for (int i = 0; i < sheetNum; i++) {
                //创建Sheet
                Sheet sheet = new Sheet(i, 0);
                sheet.setSheetName("测试Sheet1" + i);
                //循环写入次数: j的自增条件是当不是最后一个Sheet的时候写入次数为正常的每个Sheet写入的次数,如果是最后一个就需要使用计算的次数lastSheetWriteCount
                for (int j = 0; j < (i != sheetNum - 1 ? oneSheetWriteCount : lastSheetWriteCount); j++) {
                    //集合复用,便于GC清理
                    dataList.clear();
                    //分页查询一次20w
                    PageHelper.startPage(j + 1 + oneSheetWriteCount * i, writeDataRows);
                    List<ActResultLog> reslultList = actResultLogMapper.findByPage100w();
                    if (!CollectionUtils.isEmpty(reslultList)) {
                        reslultList.forEach(item -> {
                            dataList.add(Arrays.asList(item.getOnlineseqid(), item.getBusinessid(), item.getBecifno(), item.getIvisresult(), item.getCreatedby(), Calendar.getInstance().getTime().toString(), item.getUpdateby(), Calendar.getInstance().getTime().toString(), item.getRisklevel()));
                        });
                    }
                    //写数据
                    writer.write0(dataList, sheet, table);
                }
            }

            // 下载EXCEL
            response.setHeader("Content-Disposition", "attachment;filename=" + new String((fileName).getBytes("gb2312"), "ISO-8859-1") + ".xlsx");
            response.setContentType("multipart/form-data");
            response.setCharacterEncoding("utf-8");
            writer.finish();
            outputStream.flush();
            //导出时间结束
            long endTime = System.currentTimeMillis();
            System.out.println("导出结束时间:" + endTime + "ms");
            System.out.println("导出所用时间:" + (endTime - startTime) / 1000 + "秒");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

3.2.1 Status da máquina de teste

O seguinte é a configuração da máquina de teste

3.2.2 Usando a versão do banco de dados

O banco de dados que utilizo é o Oracle19C.Na verdade, quando a quantidade de dados não ultrapassa 100 milhões, o desempenho do Mysql e do Oracle não é muito diferente.Se ultrapassar 100 milhões, as vantagens do Oracle em todos os aspectos serão óbvias.

Portanto, o impacto do uso do banco de dados no tempo pode ser ignorado aqui, e o teste pode ser concluído usando o mysql sem instalar o Oracle separadamente.

Neste teste, em termos de consulta, usei a consulta simulada de 3 milhões de dados por rownum. Esse tipo de consulta não é muito eficiente. Na verdade, ainda há muito espaço para otimização para acelerar a consulta.

Por exemplo: consultar campos específicos com clareza, não usar asteriscos, consultar campos com frequência e adicionar índices para melhorar ao máximo a eficiência da consulta, e o tempo pode ser menor.

<select id="findByPage300w" resultType="show.mrkay.pojo.ActResultLog">
    select *
    from ACT_RESULT_LOG
    where rownum <![CDATA[<]]> 3000001
</select>
-- 建表语句:可以参考一下
-- Create table
create table ACT_RESULT_LOG
(
  onlineseqid VARCHAR2(32),
  businessid  VARCHAR2(32),
  becifno     VARCHAR2(32),
  ivisresult  VARCHAR2(32),
  createdby   VARCHAR2(32),
  createddate DATE,
  updateby    VARCHAR2(32),
  updateddate DATE,
  risklevel   VARCHAR2(32)
)
tablespace STUDY_KAY
  pctfree 10
  initrans 1
  maxtrans 255
  storage
  (
    initial 64K
    next 1M
    minextents 1
    maxextents unlimited
  );

3.2.3 Resultados do teste

O seguinte é o tempo que leva para os dados de 300w serem exportados do banco de dados para o Excel

A partir dos resultados acima, pode-se ver que o tempo de exportação de dados de 300w leva 2 minutos e 15 segundos, e isso ocorre quando a entidade não é usada como mapeamento. Se o mapeamento de entidade não for aplicável ao encapsulamento do loop, a velocidade será mais rápido (claro, isso também ocorre na ausência de Ao definir outros estilos de tabela, como cabeçalhos de tabela)

No geral, a velocidade não é ruim.

Depois de verificar muitas informações na Internet, um blogueiro testou que levava 105 segundos para exportar dados de 102w usando o EasyExcel. Para obter detalhes, consulte o link:

https://blog.csdn.net/u014299266/article/details/107790561

Observe o efeito da exportação: o arquivo ainda é bastante grande com 163M

3.2.4 Exportar resumo

Após o teste, o EasyExcel ainda é muito rápido e é bastante conveniente de usar. O autor também fornece um método especial para fechar o fluxo, que não exige que fechemos o fluxo manualmente e também evita uma série de problemas causados ​​por nós muitas vezes esquecendo de fechar o fluxo.

Este é o fim do teste de exportação. Dados com um volume de dados inferior a 300 W podem ser exportados em uma Planilha. Não será demonstrado aqui.

3.3 Importação de dados de 300 W

O código não é importante, a ideia é a primeira

Soluções de importação de dados de 300 W

1. O primeiro passo é ler os dados de 300w no Excel em lotes. O EasyExcel tem uma solução própria para isso. Podemos consultar o Demo. Só precisamos aumentar o parâmetro 3000 em lotes. Eu uso 20w; (você pode entender o código depois de um tempo)

2. A segunda é inserir no banco de dados. Como inserir esses 200.000 dados, é claro, você não pode repetir um por um. Você deve inserir esses 200.000 dados em lotes. Além disso, você não pode usar a linguagem de inserção em lote do Mybatis, porque a eficiência também é baixa. Você pode consultar o seguinte link [Comparação de desempenho entre inserção em lote Myabtis e inserção em lote JDBC]

3. Use a operação em lote da transação JDBC+ para inserir dados no banco de dados. (Leitura em lote + inserção em lote JDBC + controle de transação manual)

https://www.cnblogs.com/wxw7blog/p/8706797.html

3.3.1 Dados do banco de dados (antes da importação)

como mostrado na foto

3.3.2 Código comercial principal

// EasyExcel的读取Excel数据的API
@Test
public void import2DBFromExcel10wTest() {
    String fileName = "D:\\StudyWorkspace\\JavaWorkspace\\java_project_workspace\\idea_projects\\SpringBootProjects\\easyexcel\\exportFile\\excel300w.xlsx";
    //记录开始读取Excel时间,也是导入程序开始时间
    long startReadTime = System.currentTimeMillis();
    System.out.println("------开始读取Excel的Sheet时间(包括导入数据过程):" + startReadTime + "ms------");
    //读取所有Sheet的数据.每次读完一个Sheet就会调用这个方法
    EasyExcel.read(fileName, new EasyExceGeneralDatalListener(actResultLogService2)).doReadAll();
    long endReadTime = System.currentTimeMillis();
    System.out.println("------结束读取Excel的Sheet时间(包括导入数据过程):" + endReadTime + "ms------");
}
// 事件监听
public class EasyExceGeneralDatalListener extends AnalysisEventListener<Map<Integer, String>> {
    /**
     * 处理业务逻辑的Service,也可以是Mapper
     */
    private ActResultLogService2 actResultLogService2;

    /**
     * 用于存储读取的数据
     */
    private List<Map<Integer, String>> dataList = new ArrayList<Map<Integer, String>>();

    public EasyExceGeneralDatalListener() {
    }
    
    public EasyExceGeneralDatalListener(ActResultLogService2 actResultLogService2) {
        this.actResultLogService2 = actResultLogService2;
    }
    
    @Override
    public void invoke(Map<Integer, String> data, AnalysisContext context) {
        //数据add进入集合
        dataList.add(data);
        //size是否为100000条:这里其实就是分批.当数据等于10w的时候执行一次插入
        if (dataList.size() >= ExcelConstants.GENERAL_ONCE_SAVE_TO_DB_ROWS) {
            //存入数据库:数据小于1w条使用Mybatis的批量插入即可;
            saveData();
            //清理集合便于GC回收
            dataList.clear();
        }
    }

    /**
     * 保存数据到DB
     *
     * @param
     * @MethodName: saveData
     * @return: void
     */
    private void saveData() {
        actResultLogService2.import2DBFromExcel10w(dataList);
        dataList.clear();
    }
    
    /**
     * Excel中所有数据解析完毕会调用此方法
     *
     * @param: context
     * @MethodName: doAfterAllAnalysed
     * @return: void
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        saveData();
        dataList.clear();
    }
}
//JDBC工具类
public class JDBCDruidUtils {
    private static DataSource dataSource;

    /*
   创建数据Properties集合对象加载加载配置文件
    */
    static {
        Properties pro = new Properties();
        //加载数据库连接池对象
        try {
            //获取数据库连接池对象
            pro.load(JDBCDruidUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
            dataSource = DruidDataSourceFactory.createDataSource(pro);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /*
    获取连接
     */
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }


    /**
     * 关闭conn,和 statement独对象资源
     *
     * @param connection
     * @param statement
     * @MethodName: close
     * @return: void
     */
    public static void close(Connection connection, Statement statement) {
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 关闭 conn , statement 和resultset三个对象资源
     *
     * @param connection
     * @param statement
     * @param resultSet
     * @MethodName: close
     * @return: void
     */
    public static void close(Connection connection, Statement statement, ResultSet resultSet) {
        close(connection, statement);
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /*
    获取连接池对象
     */
    public static DataSource getDataSource() {
        return dataSource;
    }

}
# druid.properties配置
driverClassName=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:ORCL
username=mrkay
password=******
initialSize=10
maxActive=50
maxWait=60000
// Service中具体业务逻辑

/**
 * 测试用Excel导入超过10w条数据,经过测试发现,使用Mybatis的批量插入速度非常慢,所以这里可以使用 数据分批+JDBC分批插入+事务来继续插入速度会非常快
 *
 * @param
 * @MethodName: import2DBFromExcel10w
 * @return: java.util.Map<java.lang.String, java.lang.Object>
 */
@Override
public Map<String, Object> import2DBFromExcel10w(List<Map<Integer, String>> dataList) {
    HashMap<String, Object> result = new HashMap<>();
    //结果集中数据为0时,结束方法.进行下一次调用
    if (dataList.size() == 0) {
        result.put("empty", "0000");
        return result;
    }
    //JDBC分批插入+事务操作完成对10w数据的插入
    Connection conn = null;
    PreparedStatement ps = null;
    try {
        long startTime = System.currentTimeMillis();
        System.out.println(dataList.size() + "条,开始导入到数据库时间:" + startTime + "ms");
        conn = JDBCDruidUtils.getConnection();
        //控制事务:默认不提交
        conn.setAutoCommit(false);
        String sql = "insert into ACT_RESULT_LOG (onlineseqid,businessid,becifno,ivisresult,createdby,createddate,updateby,updateddate,risklevel) values";
        sql += "(?,?,?,?,?,?,?,?,?)";
        ps = conn.prepareStatement(sql);
        //循环结果集:这里循环不支持"烂布袋"表达式
        for (int i = 0; i < dataList.size(); i++) {
            Map<Integer, String> item = dataList.get(i);
            ps.setString(1, item.get(0));
            ps.setString(2, item.get(1));
            ps.setString(3, item.get(2));
            ps.setString(4, item.get(3));
            ps.setString(5, item.get(4));
            ps.setTimestamp(6, new Timestamp(System.currentTimeMillis()));
            ps.setString(7, item.get(6));
            ps.setTimestamp(8, new Timestamp(System.currentTimeMillis()));
            ps.setString(9, item.get(8));
            //将一组参数添加到此 PreparedStatement 对象的批处理命令中。
            ps.addBatch();
        }
        //执行批处理
        ps.executeBatch();
        //手动提交事务
        conn.commit();
        long endTime = System.currentTimeMillis();
        System.out.println(dataList.size() + "条,结束导入到数据库时间:" + endTime + "ms");
        System.out.println(dataList.size() + "条,导入用时:" + (endTime - startTime) + "ms");
        result.put("success", "1111");
    } catch (Exception e) {
        result.put("exception", "0000");
        e.printStackTrace();
    } finally {
        //关连接
        JDBCDruidUtils.close(conn, ps);
    }
    return result;
}

3.3.3 Resultados do teste

O seguinte é o tempo para ler e gravar dados de 300w:

Calcule aproximadamente:

O tempo total desde o início da leitura até a importação do lote intermediário até o final do programa:  (1623127964725-1623127873630)/1000=91.095segundos

Os dados de 300w são inseridos exatamente 15 vezes e o tempo abrangente: 8209 milissegundos ou 8,209 segundos

O tempo calculado de leitura de dados de 300w é: 91.095-8.209=82.886segundos

O resultado é óbvio:

Demorou apenas 82,886 segundos para o EasyExcel ler dados de 300 W em lotes

O uso da operação de lote + transação JDBC para inserir 300 W de síntese de dados leva apenas 8,209 segundos

------开始读取Excel的Sheet时间(包括导入数据过程):1623127873630ms------
200000条,开始导入到数据库时间:1623127880632ms
200000条,结束导入到数据库时间:1623127881513ms
200000条,导入用时:881ms
200000条,开始导入到数据库时间:1623127886945ms
200000条,结束导入到数据库时间:1623127887429ms
200000条,导入用时:484ms
200000条,开始导入到数据库时间:1623127892894ms
200000条,结束导入到数据库时间:1623127893397ms
200000条,导入用时:503ms
200000条,开始导入到数据库时间:1623127898607ms
200000条,结束导入到数据库时间:1623127899066ms
200000条,导入用时:459ms
200000条,开始导入到数据库时间:1623127904379ms
200000条,结束导入到数据库时间:1623127904855ms
200000条,导入用时:476ms
200000条,开始导入到数据库时间:1623127910495ms
200000条,结束导入到数据库时间:1623127910939ms
200000条,导入用时:444ms
200000条,开始导入到数据库时间:1623127916271ms
200000条,结束导入到数据库时间:1623127916744ms
200000条,导入用时:473ms
200000条,开始导入到数据库时间:1623127922465ms
200000条,结束导入到数据库时间:1623127922947ms
200000条,导入用时:482ms
200000条,开始导入到数据库时间:1623127928260ms
200000条,结束导入到数据库时间:1623127928727ms
200000条,导入用时:467ms
200000条,开始导入到数据库时间:1623127934374ms
200000条,结束导入到数据库时间:1623127934891ms
200000条,导入用时:517ms
200000条,开始导入到数据库时间:1623127940189ms
200000条,结束导入到数据库时间:1623127940677ms
200000条,导入用时:488ms
200000条,开始导入到数据库时间:1623127946402ms
200000条,结束导入到数据库时间:1623127946925ms
200000条,导入用时:523ms
200000条,开始导入到数据库时间:1623127952158ms
200000条,结束导入到数据库时间:1623127952639ms
200000条,导入用时:481ms
200000条,开始导入到数据库时间:1623127957880ms
200000条,结束导入到数据库时间:1623127958925ms
200000条,导入用时:1045ms
200000条,开始导入到数据库时间:1623127964239ms
200000条,结束导入到数据库时间:1623127964725ms
200000条,导入用时:486ms
------结束读取Excel的Sheet时间(包括导入数据过程):1623127964725ms------

Veja se os dados no banco de dados estão realmente armazenados em 300w

Pode-se ver que os dados são 300W a mais do que antes da importação, e o teste é muito bem-sucedido

 

3.3.4 Resumo da importação

Especificamente, não olhei os testes de outras pessoas na Internet. Geralmente, poucas pessoas estão dispostas a testar isso, mas essa velocidade foi suficiente para eu resolver a importação e exportação de big data da empresa naquele momento. Claro , a lógica de negócios da empresa é muito complicada e a quantidade de dados é relativamente grande. Existem muitos e muitos campos na tabela. A velocidade de importação e exportação será mais lenta que o teste atual, mas também está dentro a gama aceitável de seres humanos.

4 Resumo

Os problemas encontrados neste trabalho também deixaram uma profunda impressão em mim, e também é um ponto alto da minha carreira.

No mínimo, você pode escrever em seu currículo que processou milhões de peças de importação e exportação de dados.

Finalmente, deixe-me falar sobre o que a empresa fazia antes. A prática anterior da empresa era

Limite o número de downloads por usuários, e apenas quatro pessoas podem baixar ao mesmo tempo por vez, e controle o máximo de dados de exportação de cada usuário para um máximo de 20 W. Ao mesmo tempo, eles também usam JDBC para importar em lotes , mas não controlam manualmente as transações .

Eu posso entender o controle do número de downloads simultâneos, mas controlar os dados de download para no máximo 20w parece um pouco insosso.

Esse também é um problema que resolverei mais adiante.

Acho que você gosta

Origin blog.csdn.net/wokoone/article/details/127577680
Recomendado
Clasificación