DB2中ALTER TABLE为什么需要REORG操作?

ALTER TABLE操作在日常开发中很常见,下面是摘自DB2官网关于ALTER TABLE操作的一段话。

Perhaps the most important thing to realize when running an ALTER TABLE statement containing a REORG-recommended operation is that once the ALTER TABLE statement has executed, the table will be placed in the Reorg Pending state. This means that the table is inaccessible for almost all operations until you perform a REORG. See the ALTER TABLE statement in the SQL Referencefor the complete list of ALTER TABLE operations, some of which are also called REORG-recommended operations.

简单地说就是运行ALTER TABLE时要注意当前运行的语句是否需要执行REORG操作,对于这样的ALTER TABLE语句,如果不执行REORG操作的话,基本上目标表就不再可用。至于什么样的语句需要REORG,什么样的不需要,看SQL Reference去!下面是一个具体的例子演示:

CREATE TABLE my_test AS (
    SELECT id,
       ...
       sla_priority1_time,
       sla_priority2_time,
       sla_priority3_time,
       sla_priority4_time, 
       CAST(NULL AS DECIMAL(11, 2)) AS approvedDouAmount,
       CAST(NULL AS DECIMAL(4)) AS year
      FROM fin_attributes
)
WITH NO DATA;

ALTER TABLE my_test ALTER COLUMN id SET GENERATED ALWAYS AS IDENTITY;
ALTER TABLE my_test ADD COLUMN datetime TIMESTAMP NOT NULL GENERATED BY DEFAULT FOR EACH ROW ON UPDATE AS ROW CHANGE TIMESTAMP;

ALTER TABLE my_test ALTER COLUMN sla_priority1_time DROP NOT NULL;
ALTER TABLE my_test ALTER COLUMN sla_priority2_time DROP NOT NULL;
ALTER TABLE my_test ALTER COLUMN sla_priority3_time DROP NOT NULL;

REORG TABLE my_test;

ALTER TABLE my_test ALTER COLUMN sla_priority4_time DROP NOT NULL;

REORG TABLE my_test;

INSERT INTO my_test (
       ...
       sla_priority1_time,
       sla_priority2_time,
       sla_priority3_time,
       sla_priority4_time, 
       approvedDouAmount,
       year
)
SELECT ...
       sla_priority1_time,
       sla_priority2_time,
       sla_priority3_time,
       sla_priority4_time, 
       NVL(pg.approvedDouAmount, 0),
       YEAR(NOW())
  FROM fin_attributes f, projgrp pg
 WHERE f.projgrp_id = pg.id
   AND f.project_id IS NULL
   AND f.fin_projgrp_id IS NULL
 UNION
SELECT ...
       sla_priority1_time,
       sla_priority2_time,
       sla_priority3_time,
       sla_priority4_time, 
       NVL(p.approvedDouAmount, 0),
       YEAR(NOW())
  FROM fin_attributes f, project p
 WHERE f.project_id = p.id
   AND f.projgrp_id IS NULL;

代码有四种颜色,绿色代表不需要执行REORG的语句,红色代表需要执行REORG的语句,黄色是REORG语句,白色你懂的。从代码上可以看出,红色高亮语句虽然要求使用REORG,但不及时运行REORG还可以让后续的几个语句继续执行。原因是DB2允许最多三条语句处于Reorg Pending状态,假如去除第一个REORG,语句“ALTER TABLE my_test ALTER COLUMN sla_priority4_time DROP NOT NULL;”就会执行失败。

结论:如果不确定那个是需要REORG哪个是不需要REORG,索性都用上REORG;虽然在允许有三条语句处于Reorg Pending状态,但最好每条ALTER TABLE对应一个REORG,因为处于Reorg Pending状态的表有可能会阻碍后续操作,具体详情请参考文档:http://publib.boulder.ibm.com/infocenter/db2luw/v9/index.jsp?topic=/com.ibm.db2.udb.admin.doc/doc/c0023297.htm

PS:REORG TABLE本身是DB2的command,不是正常的SQL语句(Statement)。如果在非命令行环境中想使用REORG的话,可以像下面那样调用存储过程间接执行REORG操作,执行前确保你所使用的帐号有调用这个存储过程的权限:

CALL SYSPROC.ADMIN_CMD('reorg table my_test')

最后来一段用Java动态执行SQL语句或DB2命令的代码。

//*************************************************************************** // Licensed Materials - Property of IBM // // Governed under the terms of the International // License Agreement for Non-Warranted Sample Code. // // (C) COPYRIGHT International Business Machines Corp. 1997 - 2006 // All Rights Reserved. // // US Government Users Restricted Rights - Use, duplication or // disclosure restricted by GSA ADP Schedule Contract with IBM Corp. //*************************************************************************** // // SOURCE FILE NAME: TbOnlineInx.java // // SAMPLE: How to create and reorg indexes on a table // // SQL STATEMENTS USED: // INCLUDE // CREATE INDEX // DROP INDEX // REORG // LOCK // // JAVA 2 CLASSES USED: // Statement // ResultSet // File // FileWriter // Process // BufferedReader // InputStreamReader // // Classes used from Util.java are: // Db // JdbcException // // OUTPUT FILE: TbOnlineInx.out (available in the online documentation) // Output will vary depending on the JDBC driver connectivity used. //*************************************************************************** // // For more information on the sample programs, see the README file. // // For information on developing Java applications see the Developing Java Applications book. // // For information on using SQL statements, see the SQL Reference. // // For the latest information on programming, compiling, and running DB2 // applications, visit the DB2 Information Center at // http://publib.boulder.ibm.com/infocenter/db2luw/v9/index.jsp //**************************************************************************/ import java.sql.*; import java.lang.*; import java.io.*; public class TbOnlineInx { public static void main(String argv[]) { try { Db db = new Db(argv); System.out.println(); System.out.println( "THIS SAMPLE SHOWS HOW TO CREATE AND REORG ONLINE INDEXES/n" + "ON TABLES."); // connect to the 'sample' database db.connect(); // create online index on a table createIndex(db.con); // reorg online index on a table reorgIndex(db.con); // drop online index created dropIndex(db.con); // disconnect from the 'sample' database db.disconnect(); } catch (Exception e) { JdbcException jdbcExc = new JdbcException(e); jdbcExc.handle(); } } // main // How to create an index on a table with different levels // of access to the table like read-write, read-only, no access static void createIndex(Connection conn) throws Exception { System.out.print( "/n-----------------------------------------------------------" + "/nUSE THE SQL STATEMENT/n" + " CREATE INDEX/n" + "TO CREATE AN INDEX/n"); // create an online index with read-write access to the table System.out.print( "/nTo create an index on a table allowing read-write access/n" + "to the table, use the following SQL command:/n/n" + " CREATE INDEX index1 ON employee (lastname ASC)/n"); Statement stmt = conn.createStatement(); stmt.executeUpdate("CREATE INDEX index1 ON employee (lastname ASC)"); conn.commit(); dropIndex(conn); // create an index on a table while allowing only read access to it System.out.println( "/nTo create an index on a table allowing only read access/n" + "to the table, use the following two SQL commands:/n/n" + " LOCK TABLE employee IN SHARE MODE/n" + " CREATE INDEX index1 ON employee (lastname ASC)"); stmt.executeUpdate("LOCK TABLE employee IN SHARE MODE"); conn.commit(); stmt.executeUpdate("CREATE INDEX index1 ON employee (lastname ASC)"); conn.commit(); dropIndex(conn); // create an online index allowing no access to the table System.out.println( "/nTo create an index on a table allowing no access to the /n" + "table (only uncommitted readers allowed), use the /n" + "following two SQL statements:/n/n" + " LOCK TABLE employee IN EXCLUSIVE MODE/n" + " CREATE INDEX index1 ON employee (lastname ASC)"); stmt.executeUpdate("LOCK TABLE employee IN EXCLUSIVE MODE"); conn.commit(); stmt.executeUpdate("CREATE INDEX index1 ON employee (lastname ASC)"); conn.commit(); stmt.close(); } // createIndex // Create 3 CLP files for REORG command with write, read and no access, // respectively. static void createFiles(Connection conn) throws Exception { // get fully qualified name of the table String tableName = "EMPLOYEE"; String schemaName = getSchemaName(conn, tableName); String fullTableName = schemaName + "." + tableName; // reorg command has to be executed with three different options, namely, // 'with write access', 'with read access' and 'with no access' String[] fileNames = { "ReorgCmdAllowWrite.db2", "ReorgCmdAllowRead.db2", "ReorgCmdAllowNone.db2" }; String[] options = { " WRITE ACCESS", " READ ACCESS", " NO ACCESS" }; for (int i = 0; i < 3; i++) { // create a CLP file with the REORG command and execute the file File outputFile = new File(fileNames[i]); FileWriter out = new FileWriter(outputFile); out.write("CONNECT TO SAMPLE;/n"); out.write("REORG INDEXES ALL FOR TABLE " + fullTableName + " ALLOW" + options[i] + ";/n"); out.write("CONNECT RESET;"); out.close(); // on exit, delete the temporary files created outputFile.deleteOnExit(); } } //createFiles // How to reorg an index on a table with different levels of // access to the table like read-write, read-only, no access static void reorgIndex(Connection conn) { System.out.print( "/n-----------------------------------------------------------/n" + "/nUSE THE SQL STATEMENT:/n"+ " REORG/n" + "TO REORGANIZE A TABLE./n"); String[] fileNames = { "ReorgCmdAllowWrite.db2", "ReorgCmdAllowRead.db2", "ReorgCmdAllowNone.db2" }; String[] options = { " write access", " read access", " no access" }; try { // create 3 files with REORG commands createFiles(conn); for (int i = 0; i < 3; i++) { System.out.println( "/nReorganize the indexes on a table allowing" + options[i] + "/n-----------------------------------------------------------"); String s = null; String execCmd = "db2 -tvf " + fileNames[i]; // execute the command to run the CLP file Process p = Runtime.getRuntime().exec(execCmd); // open streams for the process's input and error BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream())); BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream())); // read the output from the command and set the output variable with // the value while ((s = stdInput.readLine()) != null) { System.out.println(s); } // read any errors from the attempted command and set the error // variable with the value while ((s = stdError.readLine()) != null) { System.out.println(s); } p.destroy(); } // for } // try catch (IOException e) { e.printStackTrace(); System.exit(-1); } catch (Exception e) { JdbcException jdbcExc = new JdbcException(e); jdbcExc.handle(); } } // reorgIndex // How to drop the index on a table static void dropIndex(Connection conn) { System.out.println( "/nUSE THE SQL STATEMENT/n" + " DROP/n" + "TO DROP AN INDEX:"); try { // drop the indexes System.out.println( " Execute the statement/n" + " DROP INDEX index1/n" + "/n-----------------------------------------------------------"); Statement stmt = conn.createStatement(); stmt.executeUpdate("DROP INDEX index1"); conn.commit(); stmt.close(); } catch (Exception e) { JdbcException jdbcExc = new JdbcException(e); jdbcExc.handle(); } } // dropIndex // function to get the schema name for a particular table static String getSchemaName(Connection conn, String tableName) throws Exception { Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery( "SELECT tabschema "+ " FROM syscat.tables "+ " WHERE tabname = '"+ tableName + "'"); boolean result = rs.next(); String schemaName = rs.getString("tabschema"); rs.close(); stmt.close(); // remove the trailing white space characters from schemaName before // returning it to the calling function return schemaName.trim(); } // getSchemaName } // TbOnlineInx

你可能感兴趣的:(数据库,-,Database)