SQLServerBulkCopy大容量插入、更新操作

这篇具有很好参考价值的文章主要介绍了SQLServerBulkCopy大容量插入、更新操作。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

说明

pro环境在程序启动时需要运行50w update sql,在uat环境测试
1)分批1000每次,批量更新需要花时间120s左右;
2)采用下面类似第二个测试用例(先把数据插入临时表、临时表同步主表、删除临时表),最终只花了34s,其中插入花了14s,临时表更新到主表花了18s多
3)继承自SQLServerBulkCSVFileRecord进行大容量复制,比CachedRowSetImpl方式更快;

代码

package com.ydfind.driver.ok;

import com.microsoft.sqlserver.jdbc.SQLServerBulkCSVFileRecord;
import com.microsoft.sqlserver.jdbc.SQLServerBulkCopy;
import com.microsoft.sqlserver.jdbc.SQLServerBulkCopyOptions;
import com.microsoft.sqlserver.jdbc.SQLServerException;
import org.junit.Test;

import java.io.ByteArrayInputStream;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class MyBulkCopyTest {

    // 1w数据7332ms
    @Test
    public void testBulkInsert() throws SQLException {
        // drd notes:
        long time = System.currentTimeMillis();

        String connectionUrl = "jdbc:sqlserver://localhost:1433;databaseName=dev-data;user=sa;password=465628578";
        String tableName = "bulkCopyTest";
        String deleteSql = "if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].["
                + tableName + "]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) DROP TABLE [" + tableName + "]";
        String createSql = "create table " + tableName + " (c1 bigint, c2 varchar(20))";
        // 要插入的数据
        List<Object[]> list = new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            Object[] objects = new Object[2];
            objects[0] = Long.valueOf(i);
            objects[1] = "name_" + i;
            list.add(objects);
        }
        MySQLServerBulkRecord bulkRecord = new MySQLServerBulkRecord(list);
        bulkRecord.addColumnMetadata(1, "c1", Types.BIGINT, 19, 0);
//        bulkRecord.addColumnMetadata(1, "c1", Types.BIGINT, 19, 0);
        bulkRecord.addColumnMetadata(2, "c2", Types.VARCHAR, 20, 0);

        try (Connection connection = DriverManager.getConnection(connectionUrl);
             Statement statement = connection.createStatement();){
            connection.setAutoCommit(false);
            // 卸了旧的表
            statement.execute(deleteSql);
            // 创建新表
            statement.execute(createSql);

            // BULK INSERT
            SQLServerBulkCopyOptions options = new SQLServerBulkCopyOptions();
            options.setTableLock(true);
//            options.setBatchSize(10_0000);
            SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(connection);
            bulkCopy.setBulkCopyOptions(options);
            bulkCopy.setDestinationTableName(tableName);

            bulkCopy.writeToServer(bulkRecord);

            connection.commit();
            bulkCopy.close();
        }
        System.out.println("cost time " + (System.currentTimeMillis() - time));
    }

    public class MySQLServerBulkRecord extends SQLServerBulkCSVFileRecord {
        private List<Object[]> dataList;
        private int cur;
        public MySQLServerBulkRecord(List<Object[]> dataList) throws SQLServerException {
            super(new ByteArrayInputStream(new byte[]{}), "UTF-8", ",", false);
            this.dataList = dataList;
            cur = -1;
        }

        @Override
        public boolean next() throws SQLServerException {
            return ++cur < dataList.size();
        }

        @Override
        public Object[] getRowData() throws SQLServerException {
            if (cur >= dataList.size()) {
                return null;
            }
            return dataList.get(cur);
        }

    }

    // 更新到bulkCopyTest:先插入到临时表bulkCopyTestTemp,再update到bulkCopyTest,再删除临时表
    // 1w数据cost time 4362
    @Test
    public void testBulkUpdate() throws SQLException {
        // drd notes:
        long time = System.currentTimeMillis();

        String connectionUrl = "jdbc:sqlserver://localhost:1433;databaseName=dev-data;user=sa;password=465628578";
        String tableName = "bulkCopyTestTemp";
        String tableNameTarget = "bulkCopyTest";
        String deleteSql = "if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].["
                + tableName + "]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) DROP TABLE [" + tableName + "]";
        String createSql = "create table " + tableName + " (c1 bigint, c2 varchar(20))";
        String updateSql = "update " + tableNameTarget + " with(TABLOCK)  set c2 = t2.c2 from " + tableName + " t2 with(nolock) where " + tableNameTarget + ".c1 = t2.c1";
        // 要插入的数据
        List<Object[]> list = new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            Object[] objects = new Object[2];
            objects[0] = Long.valueOf(i);
            objects[1] = "name1_" + i;
            list.add(objects);
        }
        MySQLServerBulkRecord bulkRecord = new MySQLServerBulkRecord(list);
        bulkRecord.addColumnMetadata(1, "c1", Types.BIGINT, 19, 0);
//        bulkRecord.addColumnMetadata(1, "c1", Types.BIGINT, 19, 0);
        bulkRecord.addColumnMetadata(2, "c2", Types.VARCHAR, 20, 0);

        try (Connection connection = DriverManager.getConnection(connectionUrl);
             Statement statement = connection.createStatement();){
            connection.setAutoCommit(false);
            // 临时表
            statement.execute(deleteSql);
            statement.execute(createSql);

            SQLServerBulkCopyOptions options = new SQLServerBulkCopyOptions();
            options.setTableLock(true);
            options.setBatchSize(10_0000);
            SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(connection);
            bulkCopy.setBulkCopyOptions(options);
            bulkCopy.setDestinationTableName(tableName);

            bulkCopy.writeToServer(bulkRecord);

            // 从临时表更新到主表
            statement.execute(updateSql);
            // 删除临时表
            statement.execute(deleteSql);

            connection.commit();
            bulkCopy.close();
        }
        // 1w数据7332ms
        System.out.println("cost time " + (System.currentTimeMillis() - time));
    }
}

分析

第一个测试用例后,结果:
bulkcopy sqlserver,SqlServer,sqlserver,microsoft,sql
第二个测试用例结果
bulkcopy sqlserver,SqlServer,sqlserver,microsoft,sql

50w数据插入示例-本地电脑

package com.ydfind.driver;

import com.microsoft.sqlserver.jdbc.SQLServerBulkCopy;
import com.microsoft.sqlserver.jdbc.SQLServerBulkCopyOptions;
import com.ydfind.driver.ok.MySQLServerBulkRecord;
import org.junit.Test;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class BulkCopyInsertTest {
    private static String testTableName = "test_insert";
    private static String dropSql = "if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[" + testTableName + "]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) DROP TABLE [" + testTableName + "]";
    private static String createTableName = "create table " + testTableName + "(c1 bigint, c2 varchar(20), c3 bigint)";

    @Test
    public void testInsert() throws SQLException {
        // 1.若存在表,则删除表
        // 2.创建表
        // 3.插入10w数据
        // 4.记录插入10w数据的时间输出
        String url = "jdbc:sqlserver://localhost:1433;databaseName=rec-manager;user=sa;password=465628578";
        try (Connection conn = DriverManager.getConnection(url);
             Statement statement = conn.createStatement()) {
            statement.execute(dropSql);
            statement.execute(createTableName);

            // 插入10w条记录
            long time = System.currentTimeMillis();
            int id = 0;
            String sql = "insert into " + testTableName + "(c1, c2, c3) values(%d,'%s',%d)";
            for (int i = 0; i < 500; i++) {
                for (int j = 0; j < 1000; j++) {
                    id++;
                    String sql1 = String.format(sql, id, "name1_" + id, id);
                    statement.addBatch(sql1);
                }
                statement.executeBatch();
            }
            System.out.println("batch insert cost time = " + (System.currentTimeMillis() - time));
        }
    }

    @Test
    public void testBulkCopyInsert() throws SQLException {
        // 1.若存在表,则删除表
        // 2.创建表
        // 3.插入10w数据
        // 4.记录插入10w数据的时间输出
        String url = "jdbc:sqlserver://localhost:1433;databaseName=rec-manager;user=sa;password=465628578";
        try (Connection conn = DriverManager.getConnection(url);
             Statement statement = conn.createStatement()) {
            statement.execute(dropSql);
            statement.execute(createTableName);

            // 插入10w条记录
            long time = System.currentTimeMillis();

            List<Object[]> list = new ArrayList<>();
            for (int i = 0; i < 50_0000; i++) {
                Object[] objects = new Object[3];
                objects[0] = Long.valueOf(i);
                objects[1] = "name1_" + i;
                objects[2] = Long.valueOf(i);
                list.add(objects);
            }
            MySQLServerBulkRecord bulkRecord = new MySQLServerBulkRecord(list);
            bulkRecord.addColumnMetadata(1, "c1", Types.BIGINT, 19, 0);
            bulkRecord.addColumnMetadata(2, "c2", Types.VARCHAR, 20, 0);
            bulkRecord.addColumnMetadata(3, "c3", Types.BIGINT, 19, 0);

            SQLServerBulkCopyOptions options = new SQLServerBulkCopyOptions();
            options.setTableLock(true);
            options.setBatchSize(10000);
            SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(conn);
            bulkCopy.setBulkCopyOptions(options);
            bulkCopy.setDestinationTableName(testTableName);

            bulkCopy.writeToServer(bulkRecord);

            bulkCopy.close();
            System.out.println("bulkCopy insert cost time = " + (System.currentTimeMillis() - time));
        }
    }
}

bulkcopy sqlserver,SqlServer,sqlserver,microsoft,sql

bulkCopy insert cost time = 25052
batch insert cost time = 222397

可见bulkCopy的方式可以提升接近8倍。把executeBatch()每次的数量从1000提高到1w,执行时间也需要175495,接近3分钟。文章来源地址https://www.toymoban.com/news/detail-632489.html

到了这里,关于SQLServerBulkCopy大容量插入、更新操作的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • USB大容量存储设备无法启动该怎么办?

    USB大容量存储设备(USB mass storage device class,也称为USB MSC或UMS)是一个协议,允许一个USB接口的设备与电脑相连接,以便在两者之间传输文件。对于电脑来说,USB设备看起来就像一个移动硬盘,允许拖放型文件传送。它包括移动硬盘、闪存盘、移动光驱、读卡器、数码相机、

    2024年02月11日
    浏览(41)
  • 低成本、大容量、高交互…Polkadot 引领 GameFi 实现新突破

    有一天,你可以边打游戏边赚钱,实现 Play to earn 的梦想。 这话或许听来有些白日梦,但随着区块链行业的高速发展, DeFi、NFT 的兴起,传统游戏也在区块链行业的大背景下实现新一步的更迭。Play To earn 的理想正在加速落地,GameFi 赛道的火爆让越来越多的技术开发人员投身

    2024年02月02日
    浏览(48)
  • 买手机就要买大容量的以及为什么手机内存满了之后会变卡

    我现在手里正在用的这个是 IPhone XR,2019 年还是 2018 年买的,我记得买的时候已经上市一段时间了。这个是苹果第一款双卡双待的手机,到现在用了三四年了。 都说苹果的手机可以用很多年还很流畅,而安卓的手机一般一两年就卡的没法用,需要换了。这种说法有一定的依据

    2024年02月09日
    浏览(61)
  • 三维后处理与重建PACS源码,大容量图像存储 报告单多种模式及自定义样式

    医学影像系统源码 三维后处理与重建PACS源码 医学影像系统由PACS系统、RIS系统组成,同时提供与HIS的接口(HL7或其他类型) 。 主要功能介绍 信息预约登记 支持对患者、检查项目、申请医生、申请单据、设备等信息进行管理。且支持检查病人排队管理功能; 支持大屏幕队列

    2024年02月03日
    浏览(43)
  • 【完美解决】Windows下移动硬盘无法弹出 | 弹出USB大容量存储设备时出问题 | Windows无法停用设备 | \$Extend\$RmMetadata\$TxfLog\$TxfLog.blf

    使用U盘或者移动硬盘弹总是会遇到无法弹出的情况。此时windows往往不会告诉你具体是什么设备占用,只会提示: 弹出 USB 大容量存储设备 时出问题 或 Windows 无法停用“通用卷”设备,原因是某个程序正在使用它。关闭可能使用该设备的所有程序,然后稍后重试。 有时候我

    2024年02月11日
    浏览(68)
  • .NET 数据库大数据操作方案(插入、更新、删除、查询 、插入或更新)

    海量数据操作ORM性能瓶颈在实体转换上面,并且不能使用常规的Sql去实现 当列越多转换越慢,SqlSugar将转换性能做到极致,并且采用数据库最佳API 操作数据库达到极限性能,当然你如果不用sqlsugar了解一下原理也可以使用其他ORM实现   BulkCopy是一种用于高效批量插入大量数据

    2024年02月08日
    浏览(46)
  • 一个事务插入,另外一个事务更新操作,是否会更新成功?

    同样另外一个非常有意思的题目,值得我们思考。大概背景是这个样子的。如果有一个事务A进行插入 id 100, 同时另外一个事务B进行更新update id 100。那么事务B是否会更新成功。我们来画一个时序图: time 事务A 事务B 备注 T1 insert id 100 set status = 1 T2 update id 100 set status = 2 T3 最后

    2023年04月13日
    浏览(40)
  • C语言中实现顺序表的插入、删除和更新操作(附带源码)

    C语言中,顺序表是一种线性表的存储结构,可以通过数组来实现。以下是顺序表的插入、删除和更新操作的基本示例: 删除操作: 更新操作: 这些示例代码演示了如何在C语言中实现顺序表的插入、删除和更新操作。你可以根据需要进行修改和扩展。 希望你也学会了,更多

    2024年01月24日
    浏览(40)
  • 如何使用 Python 操作 MongoDB,包括连接、插入、查询、更新和删除数据,以及进阶用法

    MongoDB 是一种流行的 NoSQL 数据库,支持面向文档的数据存储。Python 是一种流行的编程语言,提供了许多库和工具,方便与 MongoDB 进行交互。在本文中,我们将介绍如何使用 Python 操作 MongoDB,包括连接、插入、查询、更新和删除数据,以及一些高级用法。 连接 MongoDB 在使用

    2024年02月04日
    浏览(44)
  • Java8 实现批量插入和更新,SpringBoot实现批量插入和更新,Mybatis实现批量插入和更新

    基于mybatis实现的批量插入和更新 由于直接执行批量所有数据可能会出现长度超出报错问题,使用如下方式即可解决 原理还是分配执行,这里的100就是设定每次执行最大数 这里使用插入作为例子,也可以使用批量更新 更新的写法

    2024年02月12日
    浏览(54)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包