Skip to content

Commit 925dd95

Browse files
authored
Merge pull request #2200 from ClickHouse/jmh_row_binary_datasets
[perf] RowBinary Performance Tests
2 parents 867d2b5 + 22169a6 commit 925dd95

File tree

7 files changed

+232
-8
lines changed

7 files changed

+232
-8
lines changed

performance/src/test/com/clickhouse/benchmark/BenchmarkRunner.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public static void main(String[] args) throws Exception {
3131
.param("datasetSourceName", argMap.getOrDefault("dataset", "simple"))
3232
.include(QueryClient.class.getSimpleName())
3333
.include(InsertClient.class.getSimpleName())
34-
.forks(1) // must be a fork. No fork only for debugging
34+
.forks(0) // must be a fork. No fork only for debugging
3535
.mode(Mode.AverageTime)
3636
.timeUnit(TimeUnit.MILLISECONDS)
3737
.threads(1)

performance/src/test/com/clickhouse/benchmark/clients/BenchmarkBase.java

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,20 @@
99
import com.clickhouse.client.ClickHouseCredentials;
1010
import com.clickhouse.client.ClickHouseNode;
1111
import com.clickhouse.client.ClickHouseProtocol;
12+
import com.clickhouse.client.ClickHouseResponse;
1213
import com.clickhouse.client.ClickHouseServerForTest;
1314
import com.clickhouse.client.api.Client;
1415
import com.clickhouse.client.api.data_formats.ClickHouseBinaryFormatReader;
1516
import com.clickhouse.client.api.enums.Protocol;
1617
import com.clickhouse.client.api.insert.InsertResponse;
18+
import com.clickhouse.client.api.metadata.TableSchema;
19+
import com.clickhouse.data.ClickHouseDataProcessor;
1720
import com.clickhouse.client.api.query.GenericRecord;
1821
import com.clickhouse.client.api.query.QueryResponse;
1922
import com.clickhouse.data.ClickHouseFormat;
23+
import com.clickhouse.data.ClickHouseOutputStream;
24+
import com.clickhouse.data.ClickHouseRecord;
25+
import com.clickhouse.data.format.ClickHouseRowBinaryProcessor;
2026
import org.openjdk.jmh.annotations.Level;
2127
import org.openjdk.jmh.annotations.Param;
2228
import org.openjdk.jmh.annotations.Scope;
@@ -26,7 +32,10 @@
2632
import org.slf4j.Logger;
2733
import org.slf4j.LoggerFactory;
2834

35+
import java.io.ByteArrayOutputStream;
2936
import java.io.InputStream;
37+
import java.util.ArrayList;
38+
import java.util.Collections;
3039
import java.math.BigInteger;
3140
import java.util.List;
3241

@@ -75,7 +84,6 @@ public void setup(DataState dataState, boolean insertData) throws Exception {
7584
dataState.datasetSourceName = "simple";
7685
dataState.dataSet = new SimpleDataSet();
7786
} else if (dataState.datasetSourceName.startsWith("file://")) {
78-
7987
dataState.dataSet = new FileDataSet(dataState.datasetSourceName.substring("file://".length()));
8088
dataState.datasetSourceName = dataState.dataSet.getName();
8189
}
@@ -157,4 +165,30 @@ protected static Client getClientV2(boolean useDatabase) {
157165
.setDefaultDatabase(useDatabase ? DB_NAME : "default")
158166
.build();
159167
}
168+
169+
public static void loadClickHouseRecords(String tableName, DataSet dataSet) {
170+
ClickHouseNode node = getServer();
171+
172+
try (ClickHouseClient clientV1 = ClickHouseClient
173+
.newInstance(ClickHouseCredentials.fromUserAndPassword(getUsername(), getPassword()), ClickHouseProtocol.HTTP);
174+
ClickHouseResponse response = clientV1.read(node).query("SELECT * FROM " + DB_NAME + "." + tableName)
175+
.format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
176+
.executeAndWait()) {
177+
178+
// Create a data processor to serialize data in ClientV1 tests
179+
ClickHouseDataProcessor dataProcessor= new ClickHouseRowBinaryProcessor(clientV1.getConfig(), null,
180+
ClickHouseOutputStream.of(new ByteArrayOutputStream()), response.getColumns(), Collections.emptyMap());
181+
assert dataProcessor.getColumns() != null;
182+
dataSet.setClickHouseDataProcessor(dataProcessor);
183+
ArrayList<ClickHouseRecord> records = new ArrayList<>();
184+
for (ClickHouseRecord record : response.records()) {
185+
records.add(record);
186+
}
187+
188+
dataSet.setClickHouseRecords(records);
189+
} catch (Exception e) {
190+
LOGGER.error("Error inserting data: ", e);
191+
throw new RuntimeException("Error inserting data", e);
192+
}
193+
}
160194
}

performance/src/test/com/clickhouse/benchmark/clients/InsertClient.java

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,19 @@
22

33
import com.clickhouse.client.ClickHouseResponse;
44
import com.clickhouse.client.ClickHouseResponseSummary;
5+
import com.clickhouse.client.api.Client;
6+
import com.clickhouse.client.api.data_formats.ClickHouseBinaryFormatReader;
7+
import com.clickhouse.client.api.data_formats.RowBinaryFormatWriter;
8+
import com.clickhouse.client.api.enums.Protocol;
59
import com.clickhouse.client.api.insert.InsertResponse;
610
import com.clickhouse.client.api.insert.InsertSettings;
11+
import com.clickhouse.client.api.query.QueryResponse;
712
import com.clickhouse.client.config.ClickHouseClientOption;
13+
import com.clickhouse.data.ClickHouseColumn;
14+
import com.clickhouse.data.ClickHouseDataProcessor;
815
import com.clickhouse.data.ClickHouseFormat;
16+
import com.clickhouse.data.ClickHouseRecord;
17+
import com.clickhouse.data.ClickHouseSerializer;
918
import org.openjdk.jmh.annotations.Benchmark;
1019
import org.openjdk.jmh.annotations.Level;
1120
import org.openjdk.jmh.annotations.Scope;
@@ -15,6 +24,12 @@
1524
import org.slf4j.Logger;
1625
import org.slf4j.LoggerFactory;
1726

27+
import java.math.BigInteger;
28+
import java.util.List;
29+
import java.util.Map;
30+
31+
import static com.clickhouse.client.ClickHouseServerForTest.isCloud;
32+
1833
@State(Scope.Benchmark)
1934
public class InsertClient extends BenchmarkBase {
2035
private static final Logger LOGGER = LoggerFactory.getLogger(InsertClient.class);
@@ -30,7 +45,6 @@ public void tearDownIteration(DataState dataState) throws InterruptedException {
3045
verifyRowsInsertedAndCleanup(dataState.dataSet);
3146
}
3247

33-
3448
@Benchmark
3549
public void insertV1(DataState dataState) {
3650
try {
@@ -75,4 +89,90 @@ public void insertV2(DataState dataState) {
7589
LOGGER.error("Error: ", e);
7690
}
7791
}
92+
93+
@Benchmark
94+
public void insertV1RowBinary(DataState dataState) {
95+
try {
96+
ClickHouseFormat format = ClickHouseFormat.RowBinary;
97+
try (ClickHouseResponse response = clientV1.read(getServer())
98+
.write()
99+
.option(ClickHouseClientOption.ASYNC, false)
100+
.format(format)
101+
.query("INSERT INTO `" + DB_NAME + "`.`" + dataState.dataSet.getTableName() + "`")
102+
.data(out -> {
103+
ClickHouseDataProcessor p = dataState.dataSet.getClickHouseDataProcessor();
104+
ClickHouseSerializer[] serializers = p.getSerializers(clientV1.getConfig(), p.getColumns());
105+
106+
for (ClickHouseRecord record : dataState.dataSet.getClickHouseRecords()) {
107+
for (int i = 0; i < serializers.length; i++) {
108+
serializers[i].serialize(record.getValue(i), out);
109+
}
110+
}
111+
112+
})
113+
.executeAndWait()) {
114+
ClickHouseResponseSummary summary = response.getSummary();
115+
if (summary.getWrittenRows() <= 0) {
116+
throw new RuntimeException("Rows written: " + summary.getWrittenRows());
117+
}
118+
}
119+
} catch ( Exception e) {
120+
LOGGER.error("Error: ", e);
121+
}
122+
}
123+
124+
@Benchmark
125+
public void insertV2RowBinary(DataState dataState) {
126+
try {
127+
try (InsertResponse response = clientV2.insert(dataState.dataSet.getTableName(), out -> {
128+
RowBinaryFormatWriter w = new RowBinaryFormatWriter(out, dataState.dataSet.getSchema(), ClickHouseFormat.RowBinary);
129+
List<ClickHouseColumn> columns = dataState.dataSet.getSchema().getColumns();
130+
for (Map<String, Object> row : dataState.dataSet.getRows()) {
131+
for (ClickHouseColumn column : columns) {
132+
w.setValue(column.getColumnName(),row.get(column.getColumnName()));
133+
}
134+
w.commitRow();
135+
}
136+
out.flush();
137+
138+
}, ClickHouseFormat.RowBinaryWithDefaults, new InsertSettings()).get()) {
139+
if (response.getWrittenRows() <= 0) {
140+
throw new RuntimeException("Rows written: " + response.getWrittenRows());
141+
}
142+
}
143+
} catch (Exception e) {
144+
LOGGER.error("Error: ", e);
145+
}
146+
}
147+
148+
// @Benchmark
149+
// public void insertV1WithV2RowBinaryWriter(DataState dataState) {
150+
// try {
151+
// ClickHouseFormat format = ClickHouseFormat.RowBinary;
152+
// try (ClickHouseResponse response = clientV1.read(getServer())
153+
// .write()
154+
// .option(ClickHouseClientOption.ASYNC, false)
155+
// .format(format)
156+
// .query("INSERT INTO `" + DB_NAME + "`.`" + dataState.dataSet.getTableName() + "`")
157+
// .data(out -> {
158+
// RowBinaryFormatWriter w = new RowBinaryFormatWriter(out, dataState.dataSet.getSchema(), ClickHouseFormat.RowBinary);
159+
// List<ClickHouseColumn> columns = dataState.dataSet.getSchema().getColumns();
160+
// for (Map<String, Object> row : dataState.dataSet.getRows()) {
161+
// for (ClickHouseColumn column : columns) {
162+
// w.setValue(column.getColumnName(),row.get(column.getColumnName()));
163+
// }
164+
// w.commitRow();
165+
// }
166+
// out.close();
167+
// })
168+
// .executeAndWait()) {
169+
// ClickHouseResponseSummary summary = response.getSummary();
170+
// if (summary.getWrittenRows() <= 0) {
171+
// throw new RuntimeException("Rows written: " + summary.getWrittenRows());
172+
// }
173+
// }
174+
// } catch ( Exception e) {
175+
// LOGGER.error("Error: ", e);
176+
// }
177+
// }
78178
}

performance/src/test/com/clickhouse/benchmark/data/DataSet.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package com.clickhouse.benchmark.data;
22

33
import com.clickhouse.client.api.metadata.TableSchema;
4+
import com.clickhouse.data.ClickHouseDataProcessor;
45
import com.clickhouse.data.ClickHouseFormat;
6+
import com.clickhouse.data.ClickHouseRecord;
57

68
import java.io.ByteArrayInputStream;
79
import java.io.ByteArrayOutputStream;
@@ -41,4 +43,12 @@ default InputStream getInputStream(int rowId, ClickHouseFormat format) {
4143
List<byte[]> getBytesList(ClickHouseFormat format);
4244

4345
List<Map<String, Object>> getRows();
46+
47+
List<ClickHouseRecord> getClickHouseRecords();
48+
49+
void setClickHouseRecords(List<ClickHouseRecord> records);
50+
51+
void setClickHouseDataProcessor(ClickHouseDataProcessor dataProcessor);
52+
53+
ClickHouseDataProcessor getClickHouseDataProcessor();
4454
}

performance/src/test/com/clickhouse/benchmark/data/DataSets.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,11 @@ public static TableSchema parseSchema(String createTableStatement) {//TODO: Cons
6060
public static void initializeTables(DataSet set, boolean insertData) {
6161
BenchmarkBase.runQuery(set.getCreateTableString(), true);
6262
ClickHouseFormat format = set.getFormat();
63-
if (insertData) {
64-
BenchmarkBase.insertData(set.getTableName(), set.getInputStream(format), format);
63+
64+
BenchmarkBase.insertData(set.getTableName(), set.getInputStream(format), format);
65+
if (!insertData) {
66+
BenchmarkBase.loadClickHouseRecords(set.getTableName(), set);
67+
BenchmarkBase.runQuery("TRUNCATE TABLE " + set.getTableName(), true);
6568
}
6669
}
6770

performance/src/test/com/clickhouse/benchmark/data/FileDataSet.java

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
package com.clickhouse.benchmark.data;
22

33
import com.clickhouse.client.api.metadata.TableSchema;
4+
import com.clickhouse.data.ClickHouseColumn;
5+
import com.clickhouse.data.ClickHouseDataProcessor;
46
import com.clickhouse.data.ClickHouseFormat;
7+
import com.clickhouse.data.ClickHouseRecord;
8+
import com.clickhouse.data.ClickHouseValue;
59
import org.slf4j.Logger;
610
import org.slf4j.LoggerFactory;
11+
import org.testcontainers.shaded.com.google.common.collect.Table;
712

813
import java.io.BufferedReader;
914
import java.io.File;
10-
import java.io.InputStream;
1115
import java.util.ArrayList;
1216
import java.util.Collections;
1317
import java.util.HashMap;
18+
import java.util.Iterator;
1419
import java.util.List;
1520
import java.util.Map;
1621

@@ -26,6 +31,8 @@ public class FileDataSet implements DataSet{
2631

2732
private List<byte[]> lines =null;
2833

34+
private List<Map<String, Object>> data;
35+
2936
public FileDataSet(String filePath) {
3037
File srcFile = new File(filePath);
3138

@@ -99,9 +106,10 @@ public String getTrucateTableString() {
99106
return "TRUNCATE TABLE " + getTableName();
100107
}
101108

109+
private TableSchema tableSchema = new TableSchema();
102110
@Override
103111
public TableSchema getSchema() {
104-
return schema;
112+
return tableSchema;
105113
}
106114

107115
@Override
@@ -116,14 +124,53 @@ public List<byte[]> getBytesList(ClickHouseFormat format) {
116124

117125
@Override
118126
public List<Map<String, Object>> getRows() {
119-
return Collections.emptyList();
127+
return data;
120128
}
121129

122130
@Override
123131
public ClickHouseFormat getFormat() {
124132
return ClickHouseFormat.CSV;
125133
}
126134

135+
private List<ClickHouseRecord> clickHouseRecords;
136+
137+
@Override
138+
public List<ClickHouseRecord> getClickHouseRecords() {
139+
return clickHouseRecords;
140+
}
141+
142+
@Override
143+
public void setClickHouseRecords(List<ClickHouseRecord> records) {
144+
this.clickHouseRecords = records;
145+
List<ClickHouseColumn> columns = tableSchema.getColumns();
146+
data = new ArrayList<>(records.size());
147+
for (ClickHouseRecord record : records) {
148+
Iterator<ClickHouseValue> vIter = record.iterator();
149+
int i = 0;
150+
Map<String, Object> row = new HashMap<>();
151+
while (vIter.hasNext()) {
152+
ClickHouseValue v = vIter.next();
153+
row.put(columns.get(i++).getColumnName(), v.asObject());
154+
}
155+
data.add(row);
156+
}
157+
}
158+
159+
private ClickHouseDataProcessor dataProcessor;
160+
161+
@Override
162+
public ClickHouseDataProcessor getClickHouseDataProcessor() {
163+
return dataProcessor;
164+
}
165+
166+
@Override
167+
public void setClickHouseDataProcessor(ClickHouseDataProcessor dataProcessor) {
168+
this.dataProcessor = dataProcessor;
169+
for (ClickHouseColumn column : dataProcessor.getColumns()) {
170+
tableSchema.addColumn(column.getColumnName(), column.getOriginalTypeName());
171+
}
172+
}
173+
127174
@Override
128175
public String toString() {
129176
return "FileDataSet{" +

0 commit comments

Comments
 (0)