001: package simpleorm.examples;
002:
003: import simpleorm.core.*; // .* OK, all classes prefixed with "S".
004: import java.sql.*;
005: import java.util.Random;
006: import java.util.HashMap;
007:
008: /** Basic benchmarks that compare SimpleORM performance to raw JDBC.
009: No significant degedation has been found. See the whitepaper for a
010: full description of the tests and results.<p>
011: */
012:
013: public class Benchmarks implements SConstants {
014:
015: final static int nrRows = 1000;
016: static long startTime;
017: static double timeTaken;
018:
019: public static void main(String[] argv) throws Exception {
020: TestUte.initializeTest(Benchmarks.class); // Look at this code.
021: try {
022: SLog.slog.level = 0;
023: //rawTests();
024: testInit();
025: jdbcInsert();
026: jdbcQuerySequential();
027: jdbcQueryRandom();
028: jdbcQueryField();
029: jdbcUpdateRandom();
030: jdbcUpdateBulk();
031:
032: testInit();
033: simpleormInsert();
034: simpleormQuerySequential();
035: simpleormQueryRandom();
036: simpleormQueryField();
037: simpleormUpdateRandom();
038: simpleormUpdateBulk();
039: } finally {
040: SConnection.detachAndClose();
041: }
042: }
043:
044: /** Rough simulation of key SimpleORM steps. */
045: static void rawTests() {
046: SConnection.begin();
047: startTime = System.currentTimeMillis();
048: HashMap hm = new HashMap();
049: for (int hx = 0; hx < nrRows * 10; hx++) {
050: // Empty Loop
051: //foo("zz");
052: String key = "that " + hx; // 0.004 ms
053: hm.put(key, "YYYY"); // 0.005 ms (inlc str concat)
054: hm.get(key); // 0.002 ms
055: //Connection con = SConnection.getBegunJDBCConnection();
056: }
057: SLog.slog.message("rawTests " + timeTaken());
058: }
059:
060: static boolean foo(String bar) {
061: return (bar.equals("xxx"));
062: }
063:
064: /** Prepare for tests, Delete old data. */
065: static void testInit() throws Exception {
066: SLog.slog.message("Initializing");
067: SConnection.begin();
068:
069: /// Delete any old data from a previous run.
070: try {
071: SConnection.rawUpdateDB("DROP TABLE XX_EMPLOYEE");
072: SConnection.rawUpdateDB("DROP TABLE XX_DEPARTMENT");
073: } catch (SException.JDBC ex) {
074: }
075: ; // Tables may not exist.
076: SConnection.rawUpdateDB(Department.meta.createTableSQL());
077: SConnection.rawUpdateDB(Employee.meta.createTableSQL());
078:
079: SDataLoader deptDL = new SDataLoader(Department.meta);
080: deptDL
081: .insertRecords(new Object[][] {
082: { "D100", "One00", "Count Pennies", "10000",
083: "200000" },
084: { "D200", "Two00", "Be Happy", "20000",
085: "150000" },
086: { "D300", "Three00", "Enjoy Life", "30000",
087: "100000" } });
088:
089: SConnection.commit();
090: }
091:
092: static double theTotSal;
093: static double insertTime;
094:
095: static void jdbcInsert() throws Exception {
096: SConnection.begin();
097: Connection con = SConnection.getBegunDBConnection();
098: startTime = System.currentTimeMillis();
099:
100: PreparedStatement insp = con
101: .prepareStatement("INSERT INTO XX_EMPLOYEE (EMPEE_ID, NAME, PHONE_NR, SALARY, NR_DEPENDENTS, DEPT_ID) VALUES (?, ?, ?, ?, ?, ?)");
102:
103: double totSal = 0;
104: for (int row = 0; row < nrRows; row++) {
105: insp.setString(1, row + 1000000 + "");
106: insp.setString(2, "Name " + row);
107: insp.setString(3, "(123) 456 789");
108: insp.setDouble(4, row * 100);
109: totSal += row * 100;
110: insp.setInt(5, row % 4);
111: insp.setString(6, "D" + ((row % 3) + 1) + "00");
112: insp.executeUpdate();
113: }
114:
115: SConnection.commit();
116: SLog.slog.message("jdbcInsert " + timeTaken() + " " + totSal);
117: insertTime = timeTaken;
118: theTotSal = totSal;
119: }
120:
121: static void simpleormInsert() throws Exception {
122: startTime = System.currentTimeMillis();
123: SConnection.begin();
124:
125: double totSal = 0;
126: for (int row = 0; row < nrRows; row++) {
127: Employee insp = (Employee) Employee.meta.findOrCreate(row
128: + 1000000 + "", SQY_ASSUME_CREATE);
129: insp.setString(Employee.NAME, "Name " + row);
130: insp.setString(Employee.PHONE_NR, "(123) 456 789");
131: insp.setDouble(Employee.SALARY, row * 100);
132: totSal += row * 100;
133: insp.setInt(Employee.NR_DEPENDENTS, row % 4);
134: insp.setReference(Employee.DEPARTMENT,
135: (Department) Department.meta.findOrCreate("D"
136: + ((row % 3) + 1) + "00"));
137: }
138:
139: SConnection.commit();
140: SLog.slog.message("simpleormInsert " + timeTaken() + " "
141: + totSal);
142: TestUte.assertTrue(totSal == theTotSal);
143: timeAssert(timeTaken < insertTime * 2);
144: }
145:
146: static double seqTime;
147: static double theTotBud = 0;
148:
149: static void jdbcQuerySequential() throws Exception {
150: SConnection.begin();
151: Connection con = SConnection.getBegunDBConnection();
152: startTime = System.currentTimeMillis();
153:
154: PreparedStatement selp = con
155: .prepareStatement("SELECT EMPEE_ID, E.NAME, PHONE_NR, SALARY, NR_DEPENDENTS, BUDGET FROM XX_EMPLOYEE E, XX_DEPARTMENT D WHERE E.DEPT_ID = D.DEPT_ID");
156: // Warning: this is an inner join. A better query on most DBMSs
157: // is to use a subsect which will effectively produce an outer join.
158:
159: ResultSet rs1 = selp.executeQuery();
160: double totSal = 0;
161: while (rs1.next()) {
162: String id = rs1.getString(1);
163: String name = rs1.getString(2);
164: String phone = rs1.getString(3);
165: double sal = rs1.getDouble(4);
166: totSal += sal;
167: int deps = rs1.getInt(5);
168: double bud = rs1.getDouble(6);
169: theTotBud += bud;
170: }
171: rs1.close();
172:
173: SConnection.commit();
174: SLog.slog.message("jdbcQuerySequential " + timeTaken() + " "
175: + totSal + " " + theTotBud);
176: seqTime = timeTaken;
177: TestUte.assertTrue(totSal == theTotSal);
178: }
179:
180: static void simpleormQuerySequential() throws Exception {
181: startTime = System.currentTimeMillis();
182: SConnection.begin();
183:
184: SPreparedStatement selp = Employee.meta.select((String) null,
185: null);
186: SResultSet rs1 = selp.execute();
187: double totSal = 0;
188: double totBud = 0;
189: while (rs1.hasNext()) {
190: Employee emp = (Employee) rs1.getRecord();
191: String id = emp.getString(Employee.EMPEE_ID);
192: String name = emp.getString(Employee.NAME);
193: String phone = emp.getString(Employee.PHONE_NR);
194: double sal = emp.getDouble(Employee.SALARY);
195: totSal += sal;
196: int deps = emp.getInt(Employee.NR_DEPENDENTS);
197: Department dept = (Department) emp
198: .getReference(emp.DEPARTMENT);
199: double bud = dept.getDouble(dept.BUDGET);
200: totBud += bud;
201: }
202:
203: SConnection.commit();
204: SLog.slog.message("simpleormQuerySequential " + timeTaken()
205: + " " + totSal + " " + totBud);
206: TestUte.assertTrue(totSal == theTotSal);
207: TestUte.assertTrue(totBud == theTotBud);
208: timeAssert(timeTaken < seqTime * 2);
209: }
210:
211: static double theRandTotSal;
212: static double randTime;
213:
214: static void jdbcQueryRandom() throws Exception {
215: SConnection.begin();
216: Connection con = SConnection.getBegunDBConnection();
217: startTime = System.currentTimeMillis();
218:
219: PreparedStatement selp = con
220: .prepareStatement("SELECT NAME, PHONE_NR, SALARY, NR_DEPENDENTS FROM XX_EMPLOYEE WHERE EMPEE_ID = ?");
221:
222: Random rand = new Random(0);
223: double totSal = 0;
224: for (int row = 0; row < nrRows; row++) {
225: int key = (rand.nextInt() & 0x7FFFFFFF) % nrRows + 1000000;
226: selp.setInt(1, key);
227: ResultSet rs1 = selp.executeQuery();
228: if (!rs1.next())
229: throw new SException.Test("Could not find " + key);
230: String name = rs1.getString(1);
231: String phone = rs1.getString(2);
232: double sal = rs1.getDouble(3);
233: totSal += sal;
234: int deps = rs1.getInt(4);
235: rs1.close();
236: }
237:
238: SConnection.commit();
239: SLog.slog.message("jdbcQueryRandom " + timeTaken() + " "
240: + totSal);
241: randTime = timeTaken;
242: theRandTotSal = totSal;
243: }
244:
245: static void simpleormQueryRandom() throws Exception {
246: startTime = System.currentTimeMillis();
247: SConnection.begin();
248:
249: Random rand = new Random(0);
250: double totSal = 0;
251: for (int row = 0; row < nrRows; row++) {
252: int key = (rand.nextInt() & 0x7FFFFFFF) % nrRows + 1000000;
253: Employee emp = (Employee) Employee.meta.findOrCreate(key
254: + "");
255: String id = emp.getString(Employee.EMPEE_ID);
256: String name = emp.getString(Employee.NAME);
257: String phone = emp.getString(Employee.PHONE_NR);
258: double sal = emp.getDouble(Employee.SALARY);
259: totSal += sal;
260: int deps = emp.getInt(Employee.NR_DEPENDENTS);
261: }
262:
263: SConnection.commit();
264: SLog.slog.message("simpleormQueryRandom " + timeTaken() + " "
265: + totSal);
266: TestUte.assertTrue(totSal == theRandTotSal);
267: timeAssert(timeTaken < randTime);
268: }
269:
270: static double fieldTime;
271:
272: static void jdbcQueryField() throws Exception {
273: SConnection.begin();
274: Connection con = SConnection.getBegunDBConnection();
275:
276: PreparedStatement selp = con
277: .prepareStatement("SELECT NAME, PHONE_NR, SALARY, NR_DEPENDENTS FROM XX_EMPLOYEE WHERE EMPEE_ID = ?");
278:
279: double totSal = 0;
280: selp.setInt(1, 1000000);
281: ResultSet rs1 = selp.executeQuery();
282: rs1.next();
283: startTime = System.currentTimeMillis();
284: for (int row = 0; row < nrRows * 10; row++) {
285: String name = rs1.getString(1);
286: String phone = rs1.getString(2);
287: double sal = rs1.getDouble(3);
288: totSal += sal;
289: int deps = rs1.getInt(4);
290: }
291: rs1.close();
292:
293: SConnection.commit();
294: SLog.slog.message("jdbcQueryField " + timeTaken() + "/10 "
295: + totSal);
296: fieldTime = timeTaken;
297: }
298:
299: static void simpleormQueryField() throws Exception {
300: SConnection.begin();
301:
302: double totSal = 0;
303: Employee emp = (Employee) Employee.meta.findOrCreate("1000000");
304: startTime = System.currentTimeMillis();
305: for (int row = 0; row < nrRows * 10; row++) {
306: String id = emp.getString(Employee.EMPEE_ID);
307: String name = emp.getString(Employee.NAME);
308: String phone = emp.getString(Employee.PHONE_NR);
309: double sal = emp.getDouble(Employee.SALARY);
310: totSal += sal;
311: int deps = emp.getInt(Employee.NR_DEPENDENTS);
312: }
313:
314: SConnection.commit();
315: SLog.slog.message("simpleormQueryField " + timeTaken() + "/10 "
316: + totSal);
317: timeAssert(timeTaken < fieldTime * 2);
318: }
319:
320: static double theUpdTotSal;
321: static double rupdTime;
322:
323: static void jdbcUpdateRandom() throws Exception {
324: SConnection.begin();
325: Connection con = SConnection.getBegunDBConnection();
326: startTime = System.currentTimeMillis();
327:
328: PreparedStatement selp = con
329: .prepareStatement("UPDATE XX_EMPLOYEE SET SALARY = ? WHERE EMPEE_ID = ?");
330:
331: Random rand = new Random(1);
332: double totSal = 0;
333: for (int row = 0; row < nrRows; row++) {
334: int key = (rand.nextInt() & 0x7FFFFFFF) % nrRows + 1000000;
335: selp.setInt(2, key);
336: double sal = key - 1000000;
337: totSal += sal;
338: selp.setInt(1, key);
339: selp.executeUpdate();
340: }
341:
342: SConnection.commit();
343: SLog.slog.message("jdbcUpdateRandom " + timeTaken() + " "
344: + totSal);
345: theUpdTotSal = totSal;
346: rupdTime = timeTaken;
347: }
348:
349: static void simpleormUpdateRandom() throws Exception {
350: startTime = System.currentTimeMillis();
351: SConnection.begin();
352:
353: Random rand = new Random(1);
354: double totSal = 0;
355: for (int row = 0; row < nrRows; row++) {
356: int key = (rand.nextInt() & 0x7FFFFFFF) % nrRows + 1000000;
357: Employee emp = (Employee) Employee.meta.findOrCreate(key
358: + "");
359: double sal = key - 1000000;
360: totSal += sal;
361: emp.setDouble(emp.SALARY, sal);
362: }
363:
364: SConnection.commit();
365: SLog.slog.message("simpleormUpdateRandom " + timeTaken() + " "
366: + totSal);
367: TestUte.assertTrue(totSal == theUpdTotSal);
368: timeAssert(timeTaken < rupdTime);
369: }
370:
371: static void jdbcUpdateBulk() throws Exception {
372: SConnection.begin();
373: Connection con = SConnection.getBegunDBConnection();
374: startTime = System.currentTimeMillis();
375:
376: PreparedStatement selp = con
377: .prepareStatement("UPDATE XX_EMPLOYEE SET SALARY = SALARY * 0.1");
378: selp.executeUpdate();
379:
380: SConnection.commit();
381: SLog.slog.message("jdbcUpdateBulk " + timeTaken());
382: }
383:
384: static void simpleormUpdateBulk() throws Exception {
385: SConnection.begin();
386: Connection con = SConnection.getBegunDBConnection();
387: startTime = System.currentTimeMillis();
388:
389: SConnection
390: .rawUpdateDB("UPDATE XX_EMPLOYEE SET SALARY = SALARY * 0.1");
391:
392: SConnection.commit();
393: SLog.slog.message("simpleormUpdateBulk " + timeTaken());
394: }
395:
396: static String timeTaken() {
397: timeTaken = (System.currentTimeMillis() - startTime + 0.0)
398: / nrRows;
399: return timeTaken + "";
400: }
401:
402: /** Makes timeing assertions, but only for PostgreSQL. Other
403: databases vary, especially HSQL with its in memory/checkpointing
404: model. */
405: static void timeAssert(boolean test) {
406: if (SConnection.getDriver() instanceof SDriverPostgres && !test)
407: throw new SException.Test(
408: "Result is too slow for Postgres?");
409: }
410:
411: }
|