DRUID VS ANTLR4
測試方法
環境:x86_64,eclipse kepler,jdk 6
測試對象:antlr v4,druid手寫sql parser模塊
測試過程:分別采用單線程、多線程並發測試。單線程時,比較antlr、druid各自解析1次同一條sql語句的性能;多線程(50線程)時,比較antlr、druid所有線程完成1次同一條sql解析的性能。
測試結果##
類別 | 單線程(druid比antlr) | 多線程(druid比antlr) |
簡單select | 7倍 | 6倍 |
復雜select | 約200倍 | 約1600倍 |
Insert | 6倍 | 11倍 |
Update | 15倍 | 13倍 |
Delete | 3倍 | 4倍 |
總結##
1、性能:druid好於antlr。
2、語法支持:兩者皆可實現各類語法,但antlr易於druid實現。目前發現druid沒有完全實現pg語法,如int ‘123’類型轉換。
3、可維護性:antlr好於druid 特別是體現在新增語法時,修改druid的工作量大於antlr。
4、可讀性:antlr好於druid antlr采用獨立的語法文件管理語法規則,druid語法規則與代碼耦合。
5、關鍵字支持:兩者皆支持。druid需要使用switch語句塊窮舉。
package com.laudandjolynn.test;
import java.text.NumberFormat;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.commons.cli.BasicParser;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.Options;
import com.alibaba.druid.sql.dialect.postgresql.parser.PGSQLStatementParser;
import com.laudandjolynn.idb.AntlrParser;
public class SqlParser {
private final static String ANTLR = "ANTLR";
private final static String DRUID = "DRUID";
public static void main(String[] args) throws Exception {
CommandLineParser clp = new BasicParser();
Options options = new Options();
options.addOption("t", true, "");
options.addOption("m", true, "");
options.addOption("p", true, "");
options.addOption("s", true, "");
CommandLine cl = clp.parse(options, args);
String helpMsg = "usage: java -jar test.jar -t {antlr|druid} [-m times] [-p threads] -s sql";
if (!cl.hasOption('t') || !cl.hasOption('s')) {
System.out.println(helpMsg);
System.exit(0);
}
String tool = cl.getOptionValue('t');
String sql = cl.getOptionValue('s');
int threadCount = cl.hasOption('p') ? Integer.valueOf(cl
.getOptionValue('p')) : 1;
int executeTimes = cl.hasOption('m') ? Integer.valueOf(cl
.getOptionValue('m')) : 1;
if (threadCount == 1) {
single(1, sql, tool, false);
single(executeTimes, sql, tool, true);
} else {
multiple(1, sql, tool, 1, false);
multiple(executeTimes, sql, tool, threadCount, true);
}
System.exit(0);
}
private static void single(int executeTimes, String sql, String tool,
boolean stat) {
long sum = 0;
long max = Long.MIN_VALUE;
long min = Long.MAX_VALUE;
int maxIndex = -1;
for (int j = 0; j < executeTimes; j++) {
long start = System.nanoTime();
parse(sql, tool);
long elapse = System.nanoTime() - start;
if (max < elapse) {
max = elapse;
maxIndex = j;
}
if (min > elapse) {
min = elapse;
}
sum += elapse;
}
if (stat) {
NumberFormat format = NumberFormat.getInstance();
format.setMaximumFractionDigits(3);
System.out.println("max: " + format.format(max / 1000000.0)
+ " ms. max value index: " + maxIndex);
System.out
.println("min: " + format.format(min / 1000000.0) + " ms");
System.out.println("avg: "
+ format.format(sum / (double) executeTimes / 1000000.0)
+ " ms");
}
}
private static void multiple(int executeTimes, String sql, String tool,
int threadCount, boolean stat) throws Exception {
ExecutorService executorService = Executors
.newFixedThreadPool(threadCount);
CompletionService<Long[]> completionService = new ExecutorCompletionService<Long[]>(
executorService);
for (int i = 0; i < threadCount; i++) {
completionService.submit(new Parser(executeTimes, sql, tool));
}
long sum = 0;
long max = Long.MIN_VALUE;
long min = Long.MAX_VALUE;
int maxIndex = -1;
for (int i = 0; i < threadCount; i++) {
Long[] elapses = completionService.take().get();
for (int j = 0; j < executeTimes; j++) {
if (max < elapses[j]) {
max = elapses[j];
maxIndex = i * j;
}
if (min > elapses[j]) {
min = elapses[j];
}
sum += elapses[j];
}
}
if (stat) {
NumberFormat format = NumberFormat.getInstance();
format.setMaximumFractionDigits(3);
System.out.println("max: " + format.format(max / 1000000.0)
+ " ms. max value index: " + maxIndex);
System.out
.println("min: " + format.format(min / 1000000.0) + " ms");
System.out.println("avg: "
+ format.format(sum / executeTimes / threadCount
/ 1000000.0) + " ms");
}
}
private static class Parser implements Callable<Long[]> {
private String sql = null;
private String tool = null;
private int executeTimes;
public Parser(int executeTimes, String sql, String tool) {
this.executeTimes = executeTimes;
this.sql = sql;
this.tool = tool;
}
@Override
public Long[] call() throws Exception {
Long result[] = new Long[executeTimes];
for (int i = 0; i < executeTimes; i++) {
long start = System.nanoTime();
parse(sql, tool);
result[i] = System.nanoTime() - start;
}
return result;
}
}
private static void parse(String sql, String tool) {
if (ANTLR.equalsIgnoreCase(tool)) {
AntlrParser.parse(sql);
} else if (DRUID.equalsIgnoreCase(tool)) {
new PGSQLStatementParser(sql).parseStatement();
}
}
}