zoukankan      html  css  js  c++  java
  • 小表驱动大表语法

    select /*+ leading(s@a) use_nl(s@a,s */ stuid,courseid,score from 
    score s where s.stuid in
    (select /*+ qb_name(a) */ stuid from student where stuname in ('张三','尼古拉斯赵四')) 已选择66144行。 已用时间: 00: 00: 09.14

    常规语法:

    select stuid,courseid,score from score 

    where score.stuid in
    (select stuid from student where stuname in ('张三','尼古拉斯赵四')) 已选择66144行。 已用时间: 00: 00: 09.08

    数据选择不成功,致使比较不出差别,下次要换种方式。

    涉及的三张表:

    CREATE TABLE student(
        stuid NUMBER(8,0) NOT NULL PRIMARY KEY,
        stuname varchar(255) NOT NULL
    )
    
    INSERT INTO student(stuid,stuname) VALUES ('10', '张三');
    INSERT INTO student(stuid,stuname) VALUES ('11', '尼古拉斯赵四');
    INSERT INTO student(stuid,stuname) VALUES ('12', '王五');
    INSERT INTO student(stuid,stuname) VALUES ('13', '李六');
    
    CREATE TABLE course (
        courseid NUMBER(8,0) NOT NULL PRIMARY KEY,
        coursename varchar(255) NOT NULL
    )
    
    INSERT INTO course(courseid,coursename) VALUES ('1', '语文');
    INSERT INTO course(courseid,coursename) VALUES ('2', '数学');
    INSERT INTO course(courseid,coursename) VALUES ('3', '英语');
    
    CREATE TABLE score (
        id NUMBER(8,0) NOT NULL PRIMARY KEY,
        stuid NUMBER(8,0) NOT NULL,
        courseid NUMBER(8,0) NOT NULL,
        score NUMBER(8,0) DEFAULT 0
    )

    给大表插值的Java程序:

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.text.SimpleDateFormat;
    import java.util.ArrayList;
    import java.util.Calendar;
    import java.util.Date;
    import java.util.List;
    import java.util.Random;
    
    class TypeField{
        String type;
        String field;
    }
    
    // Insert huge records to a table
    public class HugeTbBatchInserter {
        private final int BatchSize=250;// Batch insert size
        private final int Total_Record_Count=100000000;// 最好是BatchSize的整倍数
        
        // 如果是多个表,扩充数组即可
        // PK:主键 CH:文字 DT:Datetime,RND:百以内随机数 还可以根据需要扩充代号,在getInsertSql函数中则根据代号来设置值
        private final String[][] tableArray= {
            {"score:"+Total_Record_Count,"PK:ID","RND:stuid","RND:courseid","RND:score"},
        };
        
        /**
         * 批量插值
         */
        public void batchInsert() {
            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+"...");
                
                for(String[] innerArr:tableArray) {
                    String tableName=innerArr[0].split(":")[0];
                    int existCount=fetchExistCount(tableName,stmt);
                    int maxId=fetchMaxId(tableName,stmt);
                    
                    
                    int count=Integer.parseInt(innerArr[0].split(":")[1])-existCount;
                    System.out.println("准备向表"+tableName+"插入"+count+"条记录.");
                    
                    // 插值前先清空,需要时再放开
                    // truncateTable(tableName,conn,stmt);
                    
                    // 真正插入数据
                    insertTestDataTo(tableName,maxId+1,count,innerArr,conn,stmt);
                }
            } catch (Exception e) {
                System.out.print(e.getMessage());
            } finally {
                try {
                    stmt.close();
                    conn.close();
                } catch (SQLException e) {
                    System.out.print("Can't close stmt/conn because of " + e.getMessage());
                }
            }
        }
        
        /**
         * 以当前时间为基准减去数十秒
         * @param n
         * @return
         */
        private static String getDatetimeBefore(int n) {
            try {
                Calendar now = Calendar.getInstance();
                now.add(Calendar.SECOND,-n*10);//日期减去n*10秒
                
                Date newDate=now.getTime();
                
                SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String retval = sdf.format(newDate);
                return retval;
            }
            catch(Exception ex) {
                ex.printStackTrace();
                return null;
            }
        }
        
        /**
         * 清空一个表的数据,注意此功能有破坏性,不可恢复,注意备份好数据
         * @param tableName
         * @param conn
         * @param stmt
         * @throws SQLException
         */
        private void truncateTable(String tableName,Connection conn,Statement stmt) throws SQLException{
            String sql="truncate table "+tableName;
            stmt.execute(sql);
            System.out.println("truncated table:"+tableName);
        }
        
        /**
         * 得到表中已有的最大ID值
         * @param tableName
         * @param conn
         * @param stmt
         * @return
         * @throws SQLException
         */
        private int fetchMaxId(String tableName,Statement stmt)  throws SQLException{
            String sql="select max(id) as max from "+tableName+"";
            
            ResultSet rs = stmt.executeQuery(sql);
            
            while (rs.next()) {
                int max = rs.getInt("max");
                return max;
            }
            
            return 0;
        }
        
        /**
         * 得到表中现存数量
         * @param tableName
         * @param conn
         * @param stmt
         * @return
         * @throws SQLException
         */
        private int fetchExistCount(String tableName,Statement stmt)  throws SQLException{
            String sql="select count(*) as cnt from "+tableName+"";
            
            ResultSet rs = stmt.executeQuery(sql);
            
            while (rs.next()) {
                int cnt = rs.getInt("cnt");
                return cnt;
            }
            
            return 0;
        }
        
        /**
         * 向一个表插入数据
         * @param tableName
         * @param count
         * @param innerArr
         * @param conn
         * @param stmt
         * @throws SQLException
         */
        private void insertTestDataTo(String tableName,int startId,int count,String[] innerArr,Connection conn,Statement stmt) throws SQLException{
            // 得到字段名和字段类型
            List<TypeField> typefields=new ArrayList<TypeField>();
            for(int i=1;i<innerArr.length;i++) {
                String temp=innerArr[i];
                String[] arrTmp=temp.split(":");
                
                TypeField tf=new TypeField();
                tf.type=arrTmp[0];
                tf.field=arrTmp[1];
                typefields.add(tf);
            }
            
            List<String> fields=new ArrayList<String>();
            List<String> values=new ArrayList<String>();
            int index=0;
            for(TypeField tf:typefields) {
                fields.add(tf.field);
                values.add("''{"+index+"}''");
                index++;
            }
            
            index=0;
            int times=count/BatchSize;
            for(int i=0;i<times;i++) {
                StringBuilder sb=new StringBuilder();
                sb.append("INSERT ALL ");
                
                for(int j=0;j<BatchSize;j++) {
                    index=i*BatchSize+j+startId;
                    sb.append(getInsertSql(tableName,typefields,index));
                }
                
                sb.append(" select * from dual");
                String sql = sb.toString();
                //System.out.println("sql="+sql);
                stmt.executeUpdate(sql);
                System.out.println("#"+i+"/ "+times+" "+BatchSize+" records inserted to "+tableName);
            }
        }
        
        /**
         * 得到批量插入语句
         * @param tableName
         * @param typefields
         * @param index
         * @return
         */
        private String getInsertSql(String tableName,List<TypeField> typefields,int index) {
            String currTime=getDatetimeBefore(index);
            
            StringBuilder sb=new StringBuilder();
            sb.append(" INTO "+tableName+"(");
            List<String> fields=new ArrayList<String>();
            for(TypeField tf:typefields) {
                fields.add(tf.field);
            }
            sb.append(String.join(",",fields));
            
            sb.append(") values(");
            List<String> values=new ArrayList<String>();
            for(TypeField tf:typefields) {
                if(tf.type.equals("PK")) {
                    values.add("'"+String.valueOf(index)+"'");
                }else if(tf.type.equals("CH")) {
                    values.add("'0'");
                }else if(tf.type.equals("RND")) {
                    values.add("'"+getRND()+"'");
                }else if(tf.type.equals("DT")) {
                    values.add("to_date('"+currTime+"','yyyy-MM-dd HH24:mi:ss')");
                }
            }
            sb.append(String.join(",",values));
            sb.append(")");
            
            String insertSql=sb.toString();
            return insertSql;
        }
        
        private static String getRND() {
            return getRandom(0,100);
        }
        
        private static String getRandom(int min, int max){
            Random random = new Random();
            int s = random.nextInt(max) % (max - min + 1) + min;
            return String.valueOf(s);
        }
        
    
        
        /**
         * 将秒转化为日时分秒
         * @param secondCount
         * @return
         */
        private static String sec2DHMS(long secondCount) {
            String retval = null;
        
            long days = secondCount / (60 * 60 * 24);
            long hours = (secondCount % (60 * 60 * 24)) / (60 * 60);
            long minutes = (secondCount % (60 * 60)) / 60;
            long seconds = secondCount % 60;
            
            String strSeconds="";
            if(seconds!=0) {
                strSeconds=seconds + "s";
            }
        
            if (days > 0) {
                retval = days + "d" + hours + "h" + minutes + "m" + strSeconds;
            } else if (hours > 0) {
                retval = hours + "h" + minutes + "m" + strSeconds;
            } else if (minutes > 0) {
                retval = minutes + "m" + strSeconds;
            } else {
                retval = strSeconds;
            }
        
            return retval;
        }
        
        public static void main(String[] args) {
            HugeTbBatchInserter mi=new HugeTbBatchInserter();
            long startTime = System.currentTimeMillis();
            mi.batchInsert();
            long endTime = System.currentTimeMillis();
            
            System.out.println("Time elapsed:" + sec2DHMS((endTime - startTime)/1000) );
        }
    }

    --END-- 2020年1月4日16点36分

  • 相关阅读:
    LeetCode 227. Basic Calculator II
    LeetCode 224. Basic Calculator
    LeetCode 103. Binary Tree Zigzag Level Order Traversal
    LeetCode 102. Binary Tree Level Order Traversal
    LeetCode 106. Construct Binary Tree from Inorder and Postorder Traversal
    LeetCode 105. Construct Binary Tree from Preorder and Inorder Traversal
    LeetCode 169. Majority Element
    LeetCode 145. Binary Tree Postorder Traversal
    LeetCode 94. Binary Tree Inorder Traversal
    LeetCode 144. Binary Tree Preorder Traversal
  • 原文地址:https://www.cnblogs.com/heyang78/p/12149545.html
Copyright © 2011-2022 走看看