简体   繁体   English

Teradata CLOB批处理是否对JDBC无效?

[英]Is Teradata CLOB batch processing useless with JDBC?

I think I know the answer to this question but I also want to confirm it with the experts here. 我想我知道这个问题的答案,但我也想与这里的专家确认。 I think the answer is: "Yes, because the batch size limit is 16, which is too little. So practically speaking batch processing is useless with Teradata CLOB." 我认为答案是:“是的,因为批大小限制为16,这太小了。因此,实际上,Teradata CLOB的批处理是没有用的。”

Here is my reasoning. 这是我的理由。 Here is the working Java code. 这是有效的Java代码。 I copy a table from one database connection to another using streaming 我使用流将表从一个数据库连接复制到另一个数据库连接

public class TestClob {

public void test() throws ClassNotFoundException, SQLException, IOException { 

Connection conn1, conn2; 
conn1 = DriverManager.getConnection(..., user, pass);
conn2 = DriverManager.getConnection(..., user, pass); 

Statement select = conn1.createStatement(); 
ResultSet rs = select.executeQuery("SELECT TOP 100 myClob FROM myTab " );

int totalRowNumber = 0; 

PreparedStatement ps = null; 
Clob clob = null; 
Reader clobReader = null; 

while (rs.next()) { 
totalRowNumber++; 
System.out.println(totalRowNumber);
clob = rs.getClob(1); 
clobReader = clob.getCharacterStream(); 
ps = conn2.prepareStatement("INSERT INTO myTab2 (myClob2) values (?) ");
ps.setCharacterStream(1, clobReader , clob.length() ); 
ps.execute(); // HERE I just execute the current row 
clob.free(); //  FREE the CLOB and READER objects 
clobReader.close(); 
} 

conn2.commit(); 
ps.close(); 
select.close(); 
rs.close(); 

Based on Teradata rules, I cannot have more than 16 object related to LOB open simultaneously. 根据Teradata规则,与LOB相关的对象不能同时打开超过16个。

Therefore I have to make sure that Clob clob and Reader clobReader are freed and closed respectively. 因此,我必须确保分别释放和关闭Clob clobReader clobReader

So I have two options 所以我有两个选择

1) do the executeBatch() method and have up to 16 Clob clob and Reader clobReader objects at a time. 1)执行executeBatch()方法,一次最多具有16个Clob clobReader clobReader对象。

2) do the execute() method and close Clob clob and Reader clobReader objects right after that. 2) execute()方法,然后立即关闭Clob clobReader clobReader对象。

The conclusion: Teradata CLOB batch insert is useless with JDBC. 结论:Teradata CLOB批处理插入对JDBC无效。 One cannot set a batch size of more than 16 when trying to INSERT a Clob 尝试插入Clob时,批次大小不能超过16

Please help me and let me know if I understand this correctly 请帮助我,让我知道我是否正确理解

I don't see any other ways 我没有其他办法

You can find here attached an example of batch insert of more than 16 Clobs. 您可以在此处找到超过16个Clob的批量插入示例。

 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.Reader;
 import java.io.StringReader;
 import java.security.GeneralSecurityException;
 import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
 import java.util.ArrayList;
 import java.util.List;


 public class ClobBatch {

    public static void main(String[] args) throws GeneralSecurityException, IOException, SQLException {

        String databaseCredentials = ExternalData.getCredentials();
        Connection c1=DriverManager.getConnection(databaseCredentials);
        Connection c2=DriverManager.getConnection(databaseCredentials);

        String sql="create volatile table clob_test_input ( id bigint, longobj clob) no primary index on commit preserve rows;";
        Statement s=c1.createStatement();
        s.execute(sql);

        String sql2="create volatile table clob_test_target ( id bigint, longobj clob) no primary index on commit preserve rows;";
        Statement s2=c2.createStatement();
        s2.execute(sql2);

        System.out.println("Inserting test data");
        PreparedStatement ps=c1.prepareStatement("insert into clob_test_input (id, longobj) values (?,?);"); 
        for(int i=0; i<1000; i++) {
            String st=randomLargeString();
            ps.setInt(1, i);
            ps.setCharacterStream(2, new BufferedReader(new StringReader(st)), st.length());
            ps.addBatch();
        }
        ps.executeBatch();

        System.out.println("reading test data from input table");
        Statement select=c1.createStatement();
        ResultSet rs=select.executeQuery("select * from clob_test_input");


        PreparedStatement ps2=c2.prepareStatement("insert into clob_test_target (id, longobj) values (?,?);"); 
        List<Reader> readerToClose=new ArrayList<Reader>(); 
        System.out.println("start batch creation");
        while(rs.next()) {
            int pos=rs.getInt("id");
            Reader rdr=new BufferedReader(rs.getCharacterStream("longobj"));

            StringBuffer buffer=new StringBuffer();
            int c=0;
            while((c=rdr.read())!=-1) {
                buffer.append((char)c);
            }
            rdr.close();
            ps2.setInt(1, pos);
            Reader strReader= new StringReader(buffer.toString());
            ps2.setCharacterStream(2, strReader,buffer.length());
            readerToClose.add(strReader);
            ps2.addBatch();
        }
        System.out.println("start batch execution");
        ps2.executeBatch();
        rs.close();
        c1.commit();
        c2.commit();

        for(Reader r:readerToClose) r.close();

        Statement selectTest=c2.createStatement();
        ResultSet rsTest=selectTest.executeQuery("select * from clob_test_target");
        System.out.println("show results");
        int i=0;
        while(rsTest.next()) {
            BufferedReader is=new BufferedReader(rsTest.getCharacterStream("longobj"));
            StringBuilder sb=new StringBuilder();
            int c=0;
            while((c=is.read())!=-1) {
                sb.append((char)c);
            }
            is.close();
            System.out.println(""+rsTest.getInt("id")+' '+sb.toString().substring(0,80));
        }

        rsTest.close();
    }


    private static String randomLargeString() {
        StringBuilder sb=new StringBuilder();
        for(int i=0;i<10000; i++) {
            sb.append((char) (64+Math.random()*20));
        }
        return sb.toString();
    }
 } 

I've worked on some optimistic hypothesis (eg 10000 chars Clobs) but the approach could be made less memory intensive by using temporary files instead of StringBuffers. 我已经研究了一些乐观的假设(例如10000个字符的Clobs),但是可以通过使用临时文件而不是StringBuffers来减少内存占用。

The approach is basically find some "buffer" (be it in memory or on temp files) where to keep the data from the source database, so that you can close the input ClobReader. 该方法基本上是找到一些“缓冲区”(在内存中或临时文件中),以保留源数据库中的数据,以便您可以关闭输入ClobReader。 Then you can batch insert the data from the buffer where you don't have the limitation of 16 (you still have memory limitations). 然后,您可以从没有限制16的缓冲区中批量插入数据(您仍然有内存限制)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM