昨天做了插入的单线程多线程比较,今天做个删除的。

单线程批量删除类代码:

package com.hy.delete.singlethread;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import org.apache.log4j.Logger;

import com.hy.DBParam;

/**
 * 多表单线程删除
 * Single thread table deleter
 * @author 逆火
 *
 * 2019年11月17日 上午8:42:41
 */
public class BatchDeleter {
    private static Logger log = Logger.getLogger(BatchDeleter.class);

    // Commit size
    private static final int commitSize=10000;

    private String[] tablenames= {    "TestTB01",
            "TestTB02",
            "TestTB03",
            "TestTB04",
            "TestTB05",
            "TestTB06",
            "TestTB07",
            "TestTB08",
            "TestTB09",
            "TestTB10",
            "TestTB11",
            "TestTB12",
            "TestTB13",
            "TestTB14",
            "TestTB15",
            "TestTB16",
          };

    /**
     * 批量插入
     */
    public void batchDelete(String expiredDate) {
        Connection conn = null;
        Statement stmt = null;

        try{
            Class.forName(DBParam.Driver).newInstance();
            conn = DriverManager.getConnection(DBParam.DbUrl, DBParam.User, DBParam.Pswd);
            stmt = conn.createStatement();
            System.out.println("Begin to access "+DBParam.DbUrl+" as "+DBParam.User+"...");

            int index=1;
            for(String table:tablenames) {
                int total=delete(index,table,expiredDate,conn,stmt);
                log.info("#"+index+" "+total+" records deleted from table:'"+table+"'.");
                index++;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                stmt.close();
                conn.close();
            } catch (SQLException e) {
                log.error("Can't close stmt/conn because of " + e.getMessage());
            }
        }
    }

    /**
     * change seconds to DayHourMinuteSecond format
     * @param stratMs
     * @param endMs
     * @return
     */
    private static String sec2DHMS(long stratMs,long endMs) {
        String retval = null;
        long secondCount=(endMs-stratMs)/1000;

        long days = secondCount / (60 * 60 * 24);
        long hours = (secondCount % (60 * 60 * 24)) / (60 * 60);
        long minutes = (secondCount % (60 * 60)) / 60;
        long seconds = secondCount % 60;

        if (days > 0) {
            retval = days + "d" + hours + "h" + minutes + "m" + seconds + "s";
        } else if (hours > 0) {
            retval = hours + "h" + minutes + "m" + seconds + "s";
        } else if (minutes > 0) {
            retval = minutes + "m" + seconds + "s";
        } else {
            retval = seconds + "s";
        }

        return retval;
    }

    /**
     * 按日期删一张表的记录
     * @param tableIndex
     * @param table
     * @param expiredDate
     * @param conn
     * @param stmt
     * @throws SQLException
     */
    private int delete(int tableIndex,String table,String expiredDate,Connection conn,Statement stmt) throws SQLException {
        int totalDeleted=0;
        int expiredCount=0;

        do {
            String sql="delete from "+table+" WHERE CREATEDTIME < to_date('"+expiredDate+"','yyyy-MM-dd') and rownum<'"+commitSize+"' ";
            int deleted=stmt.executeUpdate(sql);
            //log.info("#"+tableIndex+" "+deleted+" records deleted from table:'"+table+"'.");
            totalDeleted+=deleted;

            expiredCount=queryExpiredCount(table,expiredDate,stmt);
        }while(expiredCount>0);

        return totalDeleted;
    }

    /**
     * 查询过期记录数量
     * @param table
     * @param expiredDate
     * @param conn
     * @param stmt
     * @return
     * @throws SQLException
     */
    private int queryExpiredCount(String table,String expiredDate,Statement stmt) throws SQLException {
        String sql="SELECT COUNT (*) as cnt FROM "+table+" WHERE CREATEDTIME < to_date('"+expiredDate+"','yyyy-MM-dd') and rownum<10 ";

        ResultSet rs = stmt.executeQuery(sql);

        while (rs.next()) {
            int count = rs.getInt("cnt");
            return count;
        }

        return 0;
    }

    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        BatchDeleter bd=new BatchDeleter();
        bd.batchDelete("2019-07-17");
        long endTime = System.currentTimeMillis();
        log.info("Time elapsed:" + sec2DHMS(startTime,endTime) );
    }
}

输出:

Begin to access jdbc:oracle:thin:@127.0.0.1:1521:orcl as ufo...
2019-11-17 09:40:44,951 INFO[main]-#1 83077 records deleted from table:'TestTB01'.
2019-11-17 09:40:46,165 INFO[main]-#2 83077 records deleted from table:'TestTB02'.
2019-11-17 09:40:49,874 INFO[main]-#3 83077 records deleted from table:'TestTB03'.
2019-11-17 09:40:53,271 INFO[main]-#4 83077 records deleted from table:'TestTB04'.
2019-11-17 09:40:56,728 INFO[main]-#5 83077 records deleted from table:'TestTB05'.
2019-11-17 09:40:59,420 INFO[main]-#6 83077 records deleted from table:'TestTB06'.
2019-11-17 09:41:02,766 INFO[main]-#7 83077 records deleted from table:'TestTB07'.
2019-11-17 09:41:05,983 INFO[main]-#8 83077 records deleted from table:'TestTB08'.
2019-11-17 09:41:08,704 INFO[main]-#9 83077 records deleted from table:'TestTB09'.
2019-11-17 09:41:11,827 INFO[main]-#10 83077 records deleted from table:'TestTB10'.
2019-11-17 09:41:14,895 INFO[main]-#11 83077 records deleted from table:'TestTB11'.
2019-11-17 09:41:18,155 INFO[main]-#12 83077 records deleted from table:'TestTB12'.
2019-11-17 09:41:20,941 INFO[main]-#13 83077 records deleted from table:'TestTB13'.
2019-11-17 09:41:23,992 INFO[main]-#14 83077 records deleted from table:'TestTB14'.
2019-11-17 09:41:25,462 INFO[main]-#15 83077 records deleted from table:'TestTB15'.
2019-11-17 09:41:28,066 INFO[main]-#16 83077 records deleted from table:'TestTB16'.
2019-11-17 09:41:28,068 INFO[main]-Time elapsed:45s

多线程批量删除管理者类:

package com.hy.delete.multithread;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;

/**
 * 批量删表管理者
 * @author 逆火
 *
 * 2019年11月17日 上午9:54:46
 */
public class DeleteManager {
    private static Logger log = Logger.getLogger(DeleteManager.class);

    private String[] tablenames= {    "TestTB01",
            "TestTB02",
            "TestTB03",
            "TestTB04",
            "TestTB05",
            "TestTB06",
            "TestTB07",
            "TestTB08",
            "TestTB09",
            "TestTB10",
            "TestTB11",
            "TestTB12",
            "TestTB13",
            "TestTB14",
            "TestTB15",
            "TestTB16",
          };

    private long startTime;// Start time

    private List<DeleteJobInfo> jobInfos;// delete table informations

    /**
     * 批量插入
     */
    public void batchDelete(String expiredDate) {
        startTime=System.currentTimeMillis();
        jobInfos=new ArrayList<DeleteJobInfo>();

        int index=1;
        for(String table:tablenames) {
            DeleteThread dt=new DeleteThread(index,table,expiredDate,this);
            dt.start();
            index++;
        }
    }

    /**
     * Thread report manager "job done."
     * @param tbSN
     * @param tableName
     * @param timeElasped
     */
    public void reportFinished(String tbSN,String tableName,String timeElasped,String deleted) {
        jobInfos.add(new DeleteJobInfo(tbSN,tableName,timeElasped,deleted));

        if(jobInfos.size()==tablenames.length) {
            long endTime = System.currentTimeMillis();
            log.info(">>> Delete jobs finished.( time elapsed: " + sec2DHMS(startTime,endTime)+") <<<");

            log.info("------------ Details ------------");
            log.info("#,table,deleted,time elapsed");
            for(DeleteJobInfo jobInfo:jobInfos) {
                String raw="{0},{1},{2}";
                Object[] arr={jobInfo.tbSn,jobInfo.tableName,jobInfo.deleted,jobInfo.timeElapsed};
                String line=MessageFormat.format(raw, arr);
                log.info(line);
            }
            log.info("------------ Details ------------");

        }else {
            log.info(jobInfos.size()+" deleters completed their jobs.");
        }
    }

    /**
     * 成员内部类,用来做数据结构
     * 参考:https://blog.csdn.net/weixin_42762133/article/details/82890555
     * @author 逆火
     *
     * 2019年11月17日 上午9:22:04
     */
    protected static final class DeleteJobInfo{
        String tbSn;// 表序号
        String tableName;// 表名
        String timeElapsed;// 耗时
        String deleted;// count of deleted records

        public DeleteJobInfo(String tbSn,String tableName,String timeElapsed,String deleted) {
            this.tbSn=tbSn;
            this.tableName=tableName;
            this.timeElapsed=timeElapsed;
            this.deleted=deleted;
        }
    }

    /**
     * change seconds to DayHourMinuteSecond format
     * @param stratMs
     * @param endMs
     * @return
     */
    private static String sec2DHMS(long stratMs,long endMs) {
        String retval = null;
        long secondCount=(endMs-stratMs)/1000;

        long days = secondCount / (60 * 60 * 24);
        long hours = (secondCount % (60 * 60 * 24)) / (60 * 60);
        long minutes = (secondCount % (60 * 60)) / 60;
        long seconds = secondCount % 60;

        if (days > 0) {
            retval = days + "d" + hours + "h" + minutes + "m" + seconds + "s";
        } else if (hours > 0) {
            retval = hours + "h" + minutes + "m" + seconds + "s";
        } else if (minutes > 0) {
            retval = minutes + "m" + seconds + "s";
        } else {
            retval = seconds + "s";
        }

        return retval;
    }

    public static void main(String[] args) {
        DeleteManager dm=new DeleteManager();
        dm.batchDelete("2019-07-17");
    }
}

多线程删除删除者类:

package com.hy.delete.multithread;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import org.apache.log4j.Logger;

import com.hy.DBParam;

public class DeleteThread extends Thread {
    private static Logger log = Logger.getLogger(DeleteThread.class);

    // Commit size
    private static final int commitSize=10000;

    private int tableIndex;// table serial number
    private String table;// table will be deleted
    private String expiredDate;// expired date
    private DeleteManager menager; // reference to manager

    public DeleteThread(int tableIndex,String table,String expiredDate,DeleteManager menager) {
        this.tableIndex=tableIndex;
        this.table=table;
        this.expiredDate=expiredDate;
        this.menager=menager;
    }

    public void run() {
        Connection conn = null;
        Statement stmt = null;

        try{
            long startTime = System.currentTimeMillis();

            Class.forName(DBParam.Driver).newInstance();
            conn = DriverManager.getConnection(DBParam.DbUrl, DBParam.User, DBParam.Pswd);
            stmt = conn.createStatement();
            log.info("Begin to access "+DBParam.DbUrl+" as "+DBParam.User+"...");

            int total=delete(tableIndex,table,expiredDate,conn,stmt);
            log.info("#"+tableIndex+" "+total+" records deleted from table:'"+table+"'.");

            long endTime = System.currentTimeMillis();
            String timeElasped=sec2DHMS(startTime,endTime);
            menager.reportFinished(String.valueOf(tableIndex), table, timeElasped,String.valueOf(total));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                stmt.close();
                conn.close();
            } catch (SQLException e) {
                log.error("Can't close stmt/conn because of " + e.getMessage());
            }
        }
    }

     /**
     * 按日期删一张表的记录
     * @param tableIndex
     * @param table
     * @param expiredDate
     * @param conn
     * @param stmt
     * @throws SQLException
     */
    private int delete(int tableIndex,String table,String expiredDate,Connection conn,Statement stmt) throws SQLException {
        int totalDeleted=0;
        int expiredCount=0;

        do {
            String sql="delete from "+table+" WHERE CREATEDTIME < to_date('"+expiredDate+"','yyyy-MM-dd') and rownum<'"+commitSize+"' ";
            int deleted=stmt.executeUpdate(sql);
            //log.info("#"+tableIndex+" "+deleted+" records deleted from table:'"+table+"'.");
            totalDeleted+=deleted;

            expiredCount=queryExpiredCount(table,expiredDate,stmt);
        }while(expiredCount>0);

        return totalDeleted;
    }

    /**
     * 查询过期记录数量
     * @param table
     * @param expiredDate
     * @param conn
     * @param stmt
     * @return
     * @throws SQLException
     */
    private int queryExpiredCount(String table,String expiredDate,Statement stmt) throws SQLException {
        String sql="SELECT COUNT (*) as cnt FROM "+table+" WHERE CREATEDTIME < to_date('"+expiredDate+"','yyyy-MM-dd') and rownum<10 ";

        ResultSet rs = stmt.executeQuery(sql);

        while (rs.next()) {
            int count = rs.getInt("cnt");
            return count;
        }

        return 0;
    }

    /**
     * change seconds to DayHourMinuteSecond format
     * @param stratMs
     * @param endMs
     * @return
     */
    private static String sec2DHMS(long stratMs,long endMs) {
        String retval = null;
        long secondCount=(endMs-stratMs)/1000;

        long days = secondCount / (60 * 60 * 24);
        long hours = (secondCount % (60 * 60 * 24)) / (60 * 60);
        long minutes = (secondCount % (60 * 60)) / 60;
        long seconds = secondCount % 60;

        if (days > 0) {
            retval = days + "d" + hours + "h" + minutes + "m" + seconds + "s";
        } else if (hours > 0) {
            retval = hours + "h" + minutes + "m" + seconds + "s";
        } else if (minutes > 0) {
            retval = minutes + "m" + seconds + "s";
        } else {
            retval = seconds + "s";
        }

        return retval;
    }
}

这个例子也证明了多线程相对于单线程的优势。

--END-- 2019年11月17日11:24:17

【Oracle/Java】批量删除16张十万数据的表 单线程耗时45秒 多线程耗时38秒的更多相关文章

  1. 在Oracle中快速创建一张百万级别的表,一张十万级别的表 并修改两表中1%的数据 全部运行时间66秒

    万以下小表做性能优化没有多大意义,因此我需要创建大表: 创建大表有三种方法,一种是insert into table selec..connect by.的方式,它最快但是数据要么是连续值,要么是随机 ...

  2. mybatis(二)接口编程 、动态sql 、批量删除 、动态更新、连表查询

    原理等不在赘述,这里主要通过代码展现. 在mybatis(一)基础上,新建一个dao包,并在里面编写接口,然后再在xml文件中引入接口路径,其他不变,在运用阶段将比原始方法更节约时间,因为不用再去手动 ...

  3. oracle数据库,怎么给已有数据的表添加自增字段

    场景:数据仓库,ODI为使用Oracle Incremental Update IKM,需要对一事实表增加主键. 思想:基于老表创建新表,添加自增字段(序列+触发器实现),把老数据导入新表,删除老表, ...

  4. php批量删除数据库下指定前缀的表

    如何用php批量删除数据库下所有前缀为prefix_的表. 例子,统一删除前缀为“prefix_”的表. <?php //设置数据库连接信息.数据库服务器地址,数据库用户名,数据密码 mysql ...

  5. Mysql批量删除和修改某个前缀的表

    1.批量删除某个前缀的表名,首先选出这些个表. select concat( 'drop table ', table_name, ';' ) from information_schema.tabl ...

  6. 【Oracle/Java】给十六张表各插入十万条数据 单线程耗时半小时 多线程耗时一刻钟

    测试机Oracle版本: SQL> select * from v$version; BANNER ----------------------------------------------- ...

  7. 【Oracle/Java】向三张表各插入百万数据,共用时18分3秒,平均每张表6分钟

    三张表DDL如下: CREATE TABLE tb01 ( "ID" ,) not null primary key, "NAME" NVARCHAR2() n ...

  8. Java 批量删除Word中的空白段落

    1. 测试文档.期望达到的目标文档效果 用于测试的Word文档如下所示,包含的空白段落影响文章整体布局及美观性: 目标文档效果: 2. 辅助工具 2.1 使用类库:Free Spire.Doc for ...

  9. java 批量插入10万条数据

    for (int i = 0; i < 100000; i++) { dbHelper.insert("INSERT aaa(name) Values ('1')"); } ...

随机推荐

  1. Elasticsearch ES索引

    ES是一个基于RESTful web接口并且构建在Apache Lucene之上的开源分布式搜索引擎. 同时ES还是一个分布式文档数据库,其中每个字段均可被索引,而且每个字段的数据均可被搜索,能够横向 ...

  2. Linux命令——killall 、kill 、pkill、xkill

    参考:killall .kill .pkill 命令详解 Using kill, killall, and pkill 4 Ways to Kill a Process – kill, killall ...

  3. Windows——系统盘重置密码

    一.制作好系统启动U盘 软碟通自己制作即可 二.这进入到安装前界面按Shift+F10调出命令提示符 三.输入regedit后按回车进入注册表编辑器 四. 左键单击选中HKEY_LOCAL_MACHI ...

  4. Linux:入门基础

    一.操作Linux必知必会基础知识 二.在Linux命令下查看命令帮助信息 三.Linux挂机重启注销命令 四.Linux显示系统IP地址 一.操作Linux必知必会基础知识 1.Linux命令行组成 ...

  5. tinymce + vue 富文本编辑

    用texterea最多支持换行,如果文本信息想要更加丰富一些,比如增加格式样式,比如增加图片,textarea就爱莫能助了 在网上搜寻了一番,发现tinymce是比较方便好用的一款富文本编辑 http ...

  6. 用js刷剑指offer(二叉树中和为某一值的路径)

    题目描述 输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径.路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径.(注意: 在返回值的list中,数组长度大 ...

  7. 详细讲解vue.js里的父子组件通信(props和$emit)

    在进入这个话题之前,首先我们先来想一下在vue里,如何写一个父子组件.为了简单起见,下面的代码我都没用脚手架来构建项目,直接在html文件里引入vue.js来作为例子.父子组件的写法如下: <d ...

  8. Mac系统上,Firefox和Selenium不兼容的情况

    解决办法,检查环境: Python 2.7.10 Firefox 46版本 Selenium 2.53.6 注意:将Firefox自动更新关闭,否则可能会出现自动升级以后无法执行Selenium用例的 ...

  9. machine learning(10) -- classification:logistic regression cost function 和 使用 gradient descent to minimize cost function

    logistic regression cost function(single example) 图像分布 logistic regression cost function(m examples) ...

  10. msaa mrt load store action unity

    unity buildin renderpipeline 和lightweight rp 对于开了msaa的rt 的load store action设置失效 buildin的时候set render ...