Attached is a slightly modified version of the test client found in DERBY-1961. The main change I have done is to add a secondary index to it that is used for the queries. Running this with two clients on a dual CPU machine running Linux and using IBM JVM 1.5 I see a drop in throughput of about 6 percent (down from 16656 tps to 15706 tps - average of five runs).

To run this client do:

1. Create and initialize database:

    java  TestClient2 -a initdb -u "jdbc:derby:/tmp/tulldb;create=true"

2. Run test (which does SELECT * FROM ... WHERE SEC_ID= X) with two client threads:

    java TestClient2 -a select -r 60 -c 2 -u "jdbc:derby:/tmp/tulldb"

Olav

Mike Matrigali wrote:
Are these tests checked in so that I can run them in my environment?

Olav Sandstaa wrote:
The two last days I have seen a performance regression in some of the performance tests I run. For some of the tests the reduction in throughput is about 15 percent. It seems like the regression is introduced by the latest check-in on DERBY-2537, svn 531971.

I have attached a graph showing the throughput I get when running single-record select operation on a table. The queries use a secondary index for finding the record to select. The test has been run with 1 to 20 concurrent client against embedded Derby. I have run the test with and without SVN 531971. As the graph shows, the performance reduction is between 12 and 15 percent for all runs.

The schema looks like this:

CREATE TABLE t1 id INTEGER sec_id INTEGER data CHARACTER(100) PRIMARY KEY(id))
 CREATE INDEX nonprimary_index ON t1 (sec_id)

Each query do the select on the secondary index and retrieves the data field (a CHARACTER(100) field).

I would expect some of the changes done in the patch to have some influence on the performance, but not in the order of 10-15 percent.

The tests are run on a 2 CPU Opteron server running Solaris 10 and JDK 6.

Olav






------------------------------------------------------------------------



import java.sql.*;
import java.util.Random;

/*
  Test client which generates different types of load (single-record select
  operations, single-record update operations). Could be
  used for performance testing or as a load generator.

  Usage: java TestClient2 options

  Options:
    -a action (initdb, select, update)
    -d driver (default: org.apache.derby.jdbc.EmbeddedDriver)
    -u url
    -w time (warmup time in seconds, default 30)
    -r time (run time in seconds, default 300)
    -c clients (number of clients, default 1)
    -h (print this screen)

  Action and URL must always be specified.
  When running with "-a initdb", derbyTesting.jar is needed in CLASSPATH.
*/

public class TestClient2 extends Thread {
    private static String action;
    private static String driver = "org.apache.derby.jdbc.EmbeddedDriver";
    private static String url;
    private static int secondsWarmup = 30;
    private static int secondsRuntime = 300;
    private static int numberOfClients = 1;

    private static int operation;

    private static volatile boolean stop;
    private static volatile boolean collect;

    private final static int SELECT = 0;
    private final static int UPDATE = 1;
    private final static int JOIN = 2;

    private static final String[] STRINGS = new String[16];
    static {
        String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        for (int i = 0; i < STRINGS.length; i++) {
            StringBuffer buf = new StringBuffer(100);
            for (int j = i; j < i + 100; j++) {
                buf.append(chars.charAt(j % chars.length()));
            }
            STRINGS[i] = buf.toString();
        }
    }

    public static void main(String[] args) throws Exception {
        parseArgs(args);
        Class.forName(driver).newInstance();
        if (action.equals("initdb")) {
            initDb();
        } else {
            if (action.equals("select")) {
                operation = SELECT;
            } else if (action.equals("update")) {
                operation = UPDATE;
            } else {
                System.err.println("Unknown action: " + action);
                System.exit(1);
            }
            runTest();
        }
    }

    private static void parseArgs(String[] args) {
        for (int i = 0; i < args.length; i++) {
            String arg = args[i];
            if (arg.equals("-a")) {
                action = args[++i];
            } else if (arg.equals("-d")) {
                driver = args[++i];
            } else if (arg.equals("-u")) {
                url = args[++i];
            } else if (arg.equals("-w")) {
                secondsWarmup = Integer.parseInt(args[++i]);
            } else if (arg.equals("-r")) {
                secondsRuntime = Integer.parseInt(args[++i]);
            } else if (arg.equals("-c")) {
                numberOfClients = Integer.parseInt(args[++i]);
            } else if (arg.equals("-h")) {
                printUsage();
                System.exit(0);
            } else {
                System.err.println("Invalid option: " + args[i]);
                System.exit(1);
            }
        }
        if (action == null) {
            System.err.println("You must specify action.");
            System.exit(1);
        }
        if (url == null) {
            System.err.println("You must specify URL.");
            System.exit(1);
        }
    }

    private static void printUsage() {
        System.out.println("Usage: java TestClient options");
        System.out.println();
        System.out.println("Options:");
        System.out.println("  -a action (initdb, select, update)");
        System.out.println(
            "  -d driver (default: org.apache.derby.jdbc.EmbeddedDriver)");
        System.out.println("  -u url");
        System.out.println("  -w time (warmup time in seconds, default 30)");
        System.out.println("  -r time (run time in seconds, default 300)");
        System.out.println("  -c clients (number of clients, default 1)");
        System.out.println("  -h (print this screen)");
        System.out.println();
        System.out.println("Action and URL must always be specified.");
        System.out.println("When running with \"-a initdb\", " +
                           "derbyTesting.jar is needed in CLASSPATH.");
    }

    private static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url);
    }

    private static void initDb() throws SQLException {
        System.out.println("Initializing database...");

        Connection c = getConnection();
        c.setAutoCommit(false);

        Statement s = c.createStatement();

        try {
            s.executeUpdate("DROP TABLE HUNDREDKTUP");
        } catch (SQLException e) {}

        s.executeUpdate("CREATE TABLE HUNDREDKTUP(ID INT PRIMARY KEY, SEC_ID INT, " +
                        "TEXT VARCHAR(100))");

        s.executeUpdate("CREATE INDEX nonprimary_index ON HUNDREDKTUP (SEC_ID)");

        PreparedStatement ps = c.prepareStatement(
            "INSERT INTO HUNDREDKTUP VALUES (?, ?, ?)");

        for (int i = 0; i < 100000; i++) {

            ps.setInt(1, i);
            ps.setInt(2, i);
            ps.setString(3, STRINGS[i % STRINGS.length]);

            ps.executeUpdate();

            if ((i % 1000) == 999) {
                c.commit();
            }
        }

        ps.close();

        s.close();
        c.commit();
        c.close();

        System.out.println("Done.");
    }

    private static void runTest() throws InterruptedException {
        System.out.println("Starting " + action + " test with " +
                           numberOfClients + " clients...");
        TestClient2[] clients = new TestClient2[numberOfClients];
        for (int i = 0; i < clients.length; i++) {
            clients[i] = new TestClient2();
            clients[i].start();
        }
        System.out.println("Starting warmup...");
        Thread.sleep((long) secondsWarmup * 1000);
        System.out.println("Warmup finished, collecting data...");
        collect = true;
        Thread.sleep((long) secondsRuntime * 1000);
        stop = true;
        collect = false;
        System.out.println("Stopping threads...");
        long total = 0;
        for (int i = 0; i < clients.length; i++) {
            clients[i].join();
            total += clients[i].count;
        }
        System.out.println("\nTotal number of transactions: " + total);
        System.out.println("Average throughput: " +
                           ((double) total / secondsRuntime) + " TPS");
    }

    private long count;

    public void run() {
        try {
            run_();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    private void run_() throws SQLException {
        Connection c = getConnection();
        c.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
        c.setAutoCommit(false);

        Random r = new Random();

        String sql = null;

        switch (operation) {
        case SELECT:
            sql = "select * from hundredktup where sec_id = ?";
            break;
        case UPDATE:
            sql = "update hundredktup set text = ? where id = ?";
            break;
        }

        PreparedStatement ps = c.prepareStatement(sql);

        while (!stop) {
            ResultSet rs;
            switch (operation) {
            case SELECT:
                ps.setInt(1, r.nextInt(100000));
                rs = ps.executeQuery();
                rs.next();
                rs.getInt(1);
                rs.getString(2);
                rs.close();
                break;
            case UPDATE:
                ps.setString(1, STRINGS[r.nextInt(STRINGS.length)]);
                ps.setInt(2, r.nextInt(100000));
                ps.executeUpdate();
                break;
            case JOIN:
                rs = ps.executeQuery();
                while (rs.next()) {
                    rs.getInt(1);
                }
                rs.close();
                break;
            }
            c.commit();

            if (collect) {
                count++;
            }
        }

        ps.close();
        c.close();
    }
}

Reply via email to