]>
Commit | Line | Data |
---|---|---|
1d09f67e TL |
1 | /* |
2 | * Licensed to the Apache Software Foundation (ASF) under one or more | |
3 | * contributor license agreements. See the NOTICE file distributed with | |
4 | * this work for additional information regarding copyright ownership. | |
5 | * The ASF licenses this file to You under the Apache License, Version 2.0 | |
6 | * (the "License"); you may not use this file except in compliance with | |
7 | * the License. You may obtain a copy of the License at | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
11 | * Unless required by applicable law or agreed to in writing, software | |
12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | * See the License for the specific language governing permissions and | |
15 | * limitations under the License. | |
16 | */ | |
17 | ||
18 | package org.apache.arrow.adapter.jdbc; | |
19 | ||
20 | import java.sql.Connection; | |
21 | import java.sql.DriverManager; | |
22 | import java.sql.PreparedStatement; | |
23 | import java.sql.ResultSet; | |
24 | import java.sql.Statement; | |
25 | import java.util.concurrent.TimeUnit; | |
26 | ||
27 | import org.apache.arrow.adapter.jdbc.consumer.BigIntConsumer; | |
28 | import org.apache.arrow.adapter.jdbc.consumer.BitConsumer; | |
29 | import org.apache.arrow.adapter.jdbc.consumer.IntConsumer; | |
30 | import org.apache.arrow.adapter.jdbc.consumer.JdbcConsumer; | |
31 | import org.apache.arrow.adapter.jdbc.consumer.VarCharConsumer; | |
32 | import org.apache.arrow.memory.BufferAllocator; | |
33 | import org.apache.arrow.memory.RootAllocator; | |
34 | import org.apache.arrow.vector.BigIntVector; | |
35 | import org.apache.arrow.vector.BitVector; | |
36 | import org.apache.arrow.vector.IntVector; | |
37 | import org.apache.arrow.vector.VarCharVector; | |
38 | import org.apache.arrow.vector.VectorSchemaRoot; | |
39 | import org.openjdk.jmh.annotations.Benchmark; | |
40 | import org.openjdk.jmh.annotations.BenchmarkMode; | |
41 | import org.openjdk.jmh.annotations.Level; | |
42 | import org.openjdk.jmh.annotations.Mode; | |
43 | import org.openjdk.jmh.annotations.OutputTimeUnit; | |
44 | import org.openjdk.jmh.annotations.Scope; | |
45 | import org.openjdk.jmh.annotations.Setup; | |
46 | import org.openjdk.jmh.annotations.State; | |
47 | import org.openjdk.jmh.annotations.TearDown; | |
48 | import org.openjdk.jmh.runner.Runner; | |
49 | import org.openjdk.jmh.runner.RunnerException; | |
50 | import org.openjdk.jmh.runner.options.Options; | |
51 | import org.openjdk.jmh.runner.options.OptionsBuilder; | |
52 | ||
53 | /** | |
54 | * Benchmarks for Jdbc adapter. | |
55 | */ | |
56 | public class JdbcAdapterBenchmarks { | |
57 | ||
58 | private static final int VALUE_COUNT = 3000; | |
59 | ||
60 | private static final String CREATE_STATEMENT = | |
61 | "CREATE TABLE test_table (f0 INT, f1 LONG, f2 VARCHAR, f3 BOOLEAN);"; | |
62 | private static final String INSERT_STATEMENT = | |
63 | "INSERT INTO test_table (f0, f1, f2, f3) VALUES (?, ?, ?, ?);"; | |
64 | private static final String QUERY = "SELECT f0, f1, f2, f3 FROM test_table;"; | |
65 | private static final String DROP_STATEMENT = "DROP TABLE test_table;"; | |
66 | ||
67 | private static final String URL = "jdbc:h2:mem:JdbcAdapterBenchmarks"; | |
68 | private static final String DRIVER = "org.h2.Driver"; | |
69 | ||
70 | /** | |
71 | * State object for the jdbc e2e benchmark. | |
72 | */ | |
73 | @State(Scope.Benchmark) | |
74 | public static class JdbcState { | |
75 | ||
76 | private Connection conn = null; | |
77 | ||
78 | private ResultSet resultSet = null; | |
79 | ||
80 | private BufferAllocator allocator; | |
81 | ||
82 | private Statement statement; | |
83 | ||
84 | private JdbcToArrowConfig config; | |
85 | ||
86 | @Setup(Level.Trial) | |
87 | public void prepareState() throws Exception { | |
88 | allocator = new RootAllocator(Integer.MAX_VALUE); | |
89 | config = new JdbcToArrowConfigBuilder().setAllocator(allocator).setTargetBatchSize(1024).build(); | |
90 | Class.forName(DRIVER); | |
91 | conn = DriverManager.getConnection(URL); | |
92 | ||
93 | try (Statement stmt = conn.createStatement()) { | |
94 | stmt.executeUpdate(CREATE_STATEMENT); | |
95 | } | |
96 | ||
97 | for (int i = 0; i < VALUE_COUNT; i++) { | |
98 | // Insert data | |
99 | try (PreparedStatement stmt = conn.prepareStatement(INSERT_STATEMENT)) { | |
100 | ||
101 | stmt.setInt(1, i); | |
102 | stmt.setLong(2, i); | |
103 | stmt.setString(3, "test" + i); | |
104 | stmt.setBoolean(4, i % 2 == 0); | |
105 | stmt.executeUpdate(); | |
106 | } | |
107 | } | |
108 | } | |
109 | ||
110 | @Setup(Level.Invocation) | |
111 | public void prepareInvoke() throws Exception { | |
112 | statement = conn.createStatement(); | |
113 | resultSet = statement.executeQuery(QUERY); | |
114 | } | |
115 | ||
116 | @TearDown(Level.Invocation) | |
117 | public void tearDownInvoke() throws Exception { | |
118 | resultSet.close(); | |
119 | statement.close(); | |
120 | } | |
121 | ||
122 | @TearDown(Level.Trial) | |
123 | public void tearDownState() throws Exception { | |
124 | try (Statement stmt = conn.createStatement()) { | |
125 | stmt.executeUpdate(DROP_STATEMENT); | |
126 | } | |
127 | allocator.close(); | |
128 | } | |
129 | } | |
130 | ||
131 | /** | |
132 | * State object for the consume benchmark. | |
133 | */ | |
134 | @State(Scope.Benchmark) | |
135 | public static class ConsumeState { | |
136 | ||
137 | private static final boolean NULLABLE = true; | |
138 | ||
139 | private Connection conn = null; | |
140 | ||
141 | private ResultSet resultSet = null; | |
142 | ||
143 | private BufferAllocator allocator; | |
144 | ||
145 | private Statement statement; | |
146 | ||
147 | private IntVector intVector; | |
148 | ||
149 | private BigIntVector longVector; | |
150 | ||
151 | private VarCharVector varCharVector; | |
152 | ||
153 | private BitVector bitVector; | |
154 | ||
155 | private JdbcConsumer<IntVector> intConsumer; | |
156 | ||
157 | private JdbcConsumer<BigIntVector> longConsumer; | |
158 | ||
159 | private JdbcConsumer<VarCharVector> varCharConsumer; | |
160 | ||
161 | private JdbcConsumer<BitVector> bitConsumer; | |
162 | ||
163 | private JdbcToArrowConfig config; | |
164 | ||
165 | @Setup(Level.Trial) | |
166 | public void prepare() throws Exception { | |
167 | allocator = new RootAllocator(Integer.MAX_VALUE); | |
168 | config = new JdbcToArrowConfigBuilder().setAllocator(allocator).setTargetBatchSize(1024).build(); | |
169 | ||
170 | Class.forName(DRIVER); | |
171 | conn = DriverManager.getConnection(URL); | |
172 | try (Statement stmt = conn.createStatement()) { | |
173 | stmt.executeUpdate(CREATE_STATEMENT); | |
174 | } | |
175 | ||
176 | for (int i = 0; i < VALUE_COUNT; i++) { | |
177 | // Insert data | |
178 | try (PreparedStatement stmt = conn.prepareStatement(INSERT_STATEMENT)) { | |
179 | ||
180 | stmt.setInt(1, i); | |
181 | stmt.setLong(2, i); | |
182 | stmt.setString(3, "test" + i); | |
183 | stmt.setBoolean(4, i % 2 == 0); | |
184 | stmt.executeUpdate(); | |
185 | } | |
186 | } | |
187 | ||
188 | statement = conn.createStatement(); | |
189 | resultSet = statement.executeQuery(QUERY); | |
190 | resultSet.next(); | |
191 | ||
192 | intVector = new IntVector("", allocator); | |
193 | intVector.allocateNew(VALUE_COUNT); | |
194 | intConsumer = IntConsumer.createConsumer(intVector, 1, NULLABLE); | |
195 | ||
196 | longVector = new BigIntVector("", allocator); | |
197 | longVector.allocateNew(VALUE_COUNT); | |
198 | longConsumer = BigIntConsumer.createConsumer(longVector, 2, NULLABLE); | |
199 | ||
200 | varCharVector = new VarCharVector("", allocator); | |
201 | varCharVector.allocateNew(VALUE_COUNT); | |
202 | varCharConsumer = VarCharConsumer.createConsumer(varCharVector, 3, NULLABLE); | |
203 | ||
204 | bitVector = new BitVector("", allocator); | |
205 | bitVector.allocateNew(VALUE_COUNT); | |
206 | bitConsumer = BitConsumer.createConsumer(bitVector, 4, NULLABLE); | |
207 | } | |
208 | ||
209 | @TearDown(Level.Trial) | |
210 | public void tearDown() throws Exception { | |
211 | try (Statement stmt = conn.createStatement()) { | |
212 | stmt.executeUpdate(DROP_STATEMENT); | |
213 | } | |
214 | ||
215 | resultSet.close(); | |
216 | statement.close(); | |
217 | conn.close(); | |
218 | ||
219 | intVector.close(); | |
220 | intConsumer.close(); | |
221 | ||
222 | longVector.close(); | |
223 | longConsumer.close(); | |
224 | ||
225 | varCharVector.close(); | |
226 | varCharConsumer.close(); | |
227 | ||
228 | bitVector.close(); | |
229 | bitConsumer.close(); | |
230 | ||
231 | allocator.close(); | |
232 | } | |
233 | } | |
234 | ||
235 | /** | |
236 | * State object for the jdbc row consume benchmark. | |
237 | */ | |
238 | @State(Scope.Benchmark) | |
239 | public static class RowConsumeState { | |
240 | ||
241 | private Connection conn = null; | |
242 | ||
243 | private ResultSet resultSet = null; | |
244 | ||
245 | private BufferAllocator allocator; | |
246 | ||
247 | private Statement statement; | |
248 | ||
249 | private JdbcToArrowConfig config; | |
250 | ||
251 | private ArrowVectorIterator iter; | |
252 | ||
253 | private VectorSchemaRoot root; | |
254 | ||
255 | @Setup(Level.Trial) | |
256 | public void prepareState() throws Exception { | |
257 | allocator = new RootAllocator(Integer.MAX_VALUE); | |
258 | config = new JdbcToArrowConfigBuilder().setAllocator(allocator).setTargetBatchSize(VALUE_COUNT).build(); | |
259 | Class.forName(DRIVER); | |
260 | conn = DriverManager.getConnection(URL); | |
261 | ||
262 | try (Statement stmt = conn.createStatement()) { | |
263 | stmt.executeUpdate(CREATE_STATEMENT); | |
264 | } | |
265 | ||
266 | for (int i = 0; i < VALUE_COUNT; i++) { | |
267 | // Insert data | |
268 | try (PreparedStatement stmt = conn.prepareStatement(INSERT_STATEMENT)) { | |
269 | ||
270 | stmt.setInt(1, i); | |
271 | stmt.setLong(2, i); | |
272 | stmt.setString(3, "test" + i); | |
273 | stmt.setBoolean(4, i % 2 == 0); | |
274 | stmt.executeUpdate(); | |
275 | } | |
276 | } | |
277 | } | |
278 | ||
279 | @Setup(Level.Invocation) | |
280 | public void prepareInvoke() throws Exception { | |
281 | statement = conn.createStatement(); | |
282 | resultSet = statement.executeQuery(QUERY); | |
283 | ||
284 | iter = JdbcToArrow.sqlToArrowVectorIterator(resultSet, config); | |
285 | root = iter.next(); | |
286 | iter.compositeConsumer.resetVectorSchemaRoot(root); | |
287 | } | |
288 | ||
289 | @TearDown(Level.Invocation) | |
290 | public void tearDownInvoke() throws Exception { | |
291 | resultSet.close(); | |
292 | statement.close(); | |
293 | iter.close(); | |
294 | } | |
295 | ||
296 | @TearDown(Level.Trial) | |
297 | public void tearDownState() throws Exception { | |
298 | try (Statement stmt = conn.createStatement()) { | |
299 | stmt.executeUpdate(DROP_STATEMENT); | |
300 | } | |
301 | allocator.close(); | |
302 | } | |
303 | } | |
304 | ||
305 | /** | |
306 | * Test {@link JdbcToArrow#sqlToArrowVectorIterator(ResultSet, JdbcToArrowConfig)}. | |
307 | * @return useless. To avoid DCE by JIT. | |
308 | */ | |
309 | @Benchmark | |
310 | @BenchmarkMode(Mode.AverageTime) | |
311 | @OutputTimeUnit(TimeUnit.MICROSECONDS) | |
312 | public int testJdbcToArrow(JdbcState state) throws Exception { | |
313 | int valueCount = 0; | |
314 | try (ArrowVectorIterator iter = JdbcToArrow.sqlToArrowVectorIterator(state.resultSet, state.config)) { | |
315 | while (iter.hasNext()) { | |
316 | VectorSchemaRoot root = iter.next(); | |
317 | IntVector intVector = (IntVector) root.getFieldVectors().get(0); | |
318 | valueCount += intVector.getValueCount(); | |
319 | root.close(); | |
320 | } | |
321 | } | |
322 | return valueCount; | |
323 | } | |
324 | ||
325 | @Benchmark | |
326 | @BenchmarkMode(Mode.AverageTime) | |
327 | @OutputTimeUnit(TimeUnit.MICROSECONDS) | |
328 | public void consumeBenchmark(ConsumeState state) throws Exception { | |
329 | state.intConsumer.resetValueVector(state.intVector); | |
330 | state.longConsumer.resetValueVector(state.longVector); | |
331 | state.varCharConsumer.resetValueVector(state.varCharVector); | |
332 | state.bitConsumer.resetValueVector(state.bitVector); | |
333 | for (int i = 0; i < VALUE_COUNT; i++) { | |
334 | state.intConsumer.consume(state.resultSet); | |
335 | state.longConsumer.consume(state.resultSet); | |
336 | state.varCharConsumer.consume(state.resultSet); | |
337 | state.bitConsumer.consume(state.resultSet); | |
338 | } | |
339 | } | |
340 | ||
341 | @Benchmark | |
342 | @BenchmarkMode(Mode.AverageTime) | |
343 | @OutputTimeUnit(TimeUnit.MICROSECONDS) | |
344 | public void consumeRowsBenchmark(RowConsumeState state) throws Exception { | |
345 | for (int i = 0; i < VALUE_COUNT; i++) { | |
346 | state.iter.compositeConsumer.consume(state.resultSet); | |
347 | } | |
348 | } | |
349 | ||
350 | public static void main(String[] args) throws RunnerException { | |
351 | Options opt = new OptionsBuilder() | |
352 | .include(JdbcAdapterBenchmarks.class.getSimpleName()) | |
353 | .forks(1) | |
354 | .build(); | |
355 | ||
356 | new Runner(opt).run(); | |
357 | } | |
358 | } | |
359 |