1#include "benchmark_runner.hpp"
2#include "duckdb_benchmark_macro.hpp"
3#include "duckdb/main/appender.hpp"
4
5#include <random>
6
7using namespace duckdb;
8using namespace std;
9
10#define STRING_COUNT 10000000
11#define STRING_LENGTH 4
12
13#define STRING_DATA_GEN_BODY(STRING_LENGTH) \
14 static constexpr const char *chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; \
15 static string GenerateString(std::uniform_int_distribution<> &distribution, std::mt19937 &gen) { \
16 string result; \
17 for (size_t i = 0; i < STRING_LENGTH; i++) { \
18 result += string(1, chars[distribution(gen)]); \
19 } \
20 return result; \
21 } \
22 void Load(DuckDBBenchmarkState *state) override { \
23 std::uniform_int_distribution<> distribution(0, strlen(chars) - 1); \
24 std::mt19937 gen; \
25 gen.seed(42); \
26 state->conn.Query("CREATE TABLE strings(s1 VARCHAR, s2 VARCHAR);"); \
27 Appender appender(state->conn, "strings"); \
28 for (size_t i = 0; i < STRING_COUNT; i++) { \
29 appender.BeginRow(); \
30 appender.Append<Value>(Value(GenerateString(distribution, gen))); \
31 appender.Append<Value>(Value(GenerateString(distribution, gen))); \
32 appender.EndRow(); \
33 } \
34 appender.Close(); \
35 } \
36 string VerifyResult(QueryResult *result) override { \
37 if (!result->success) { \
38 return result->error; \
39 } \
40 return string(); \
41 }
42
43DUCKDB_BENCHMARK(StringConcatShort, "[string]")
44STRING_DATA_GEN_BODY(4)
45string GetQuery() override {
46 return "SELECT s1 || s2 FROM strings";
47}
48string BenchmarkInfo() override {
49 return "STRING CONCAT";
50}
51FINISH_BENCHMARK(StringConcatShort)
52
53DUCKDB_BENCHMARK(StringConcatLong, "[string]")
54STRING_DATA_GEN_BODY(20)
55string GetQuery() override {
56 return "SELECT s1 || s2 FROM strings";
57}
58string BenchmarkInfo() override {
59 return "STRING CONCAT";
60}
61FINISH_BENCHMARK(StringConcatLong)
62
63DUCKDB_BENCHMARK(StringEqualityShort, "[string]")
64STRING_DATA_GEN_BODY(4)
65string GetQuery() override {
66 return "SELECT s1=s2 FROM strings";
67}
68string BenchmarkInfo() override {
69 return "STRING COMPARISON";
70}
71FINISH_BENCHMARK(StringEqualityShort)
72
73DUCKDB_BENCHMARK(StringEqualityLong, "[string]")
74STRING_DATA_GEN_BODY(20)
75string GetQuery() override {
76 return "SELECT s1=s2 FROM strings";
77}
78string BenchmarkInfo() override {
79 return "STRING COMPARISON";
80}
81FINISH_BENCHMARK(StringEqualityLong)
82
83DUCKDB_BENCHMARK(StringGreaterThanShort, "[string]")
84STRING_DATA_GEN_BODY(4)
85string GetQuery() override {
86 return "SELECT s1>s2 FROM strings";
87}
88string BenchmarkInfo() override {
89 return "STRING COMPARISON";
90}
91FINISH_BENCHMARK(StringGreaterThanShort)
92
93DUCKDB_BENCHMARK(StringGreaterThanLong, "[string]")
94STRING_DATA_GEN_BODY(20)
95string GetQuery() override {
96 return "SELECT s1>s2 FROM strings";
97}
98string BenchmarkInfo() override {
99 return "STRING COMPARISON";
100}
101FINISH_BENCHMARK(StringGreaterThanLong)
102
103DUCKDB_BENCHMARK(StringLengthShort, "[string]")
104STRING_DATA_GEN_BODY(5)
105string GetQuery() override {
106 return "SELECT LENGTH(s1)+LENGTH(s2) FROM strings";
107}
108string BenchmarkInfo() override {
109 return "STRING LENGTH";
110}
111FINISH_BENCHMARK(StringLengthShort)
112
113DUCKDB_BENCHMARK(StringLengthLong, "[string]")
114STRING_DATA_GEN_BODY(20)
115string GetQuery() override {
116 return "SELECT LENGTH(s1)+LENGTH(s2) FROM strings";
117}
118string BenchmarkInfo() override {
119 return "STRING LENGTH";
120}
121FINISH_BENCHMARK(StringLengthLong)
122
123DUCKDB_BENCHMARK(StringAggShort, "[string]")
124STRING_DATA_GEN_BODY(4)
125string GetQuery() override {
126 return "SELECT STRING_AGG(s1, ' ') FROM strings";
127}
128string BenchmarkInfo() override {
129 return "STRING LENGTH";
130}
131FINISH_BENCHMARK(StringAggShort)
132
133DUCKDB_BENCHMARK(StringAggLong, "[string]")
134STRING_DATA_GEN_BODY(20)
135string GetQuery() override {
136 return "SELECT STRING_AGG(s1, ' ') FROM strings";
137}
138string BenchmarkInfo() override {
139 return "STRING LENGTH";
140}
141FINISH_BENCHMARK(StringAggLong)
142
143DUCKDB_BENCHMARK(StringInstr, "[string]")
144STRING_DATA_GEN_BODY(4)
145string GetQuery() override {
146 return "SELECT INSTR(s1, 'h') FROM strings";
147}
148string BenchmarkInfo() override {
149 return "STRING INSTR";
150}
151FINISH_BENCHMARK(StringInstr)
152
153DUCKDB_BENCHMARK(StringInstrNull, "[string]")
154STRING_DATA_GEN_BODY(4)
155string GetQuery() override {
156 return "SELECT INSTR(s1, '') FROM strings";
157}
158string BenchmarkInfo() override {
159 return "STRING INSTR";
160}
161FINISH_BENCHMARK(StringInstrNull)
162
163//------------------------- CONTAINS -----------------------------------------
164DUCKDB_BENCHMARK(StringContains, "[string]")
165STRING_DATA_GEN_BODY(4)
166string GetQuery() override {
167 return "SELECT CONTAINS(s1, 'h') FROM strings";
168}
169string BenchmarkInfo() override {
170 return "STRING CONTAINS";
171}
172FINISH_BENCHMARK(StringContains)
173
174DUCKDB_BENCHMARK(StringContainsNull, "[string]")
175STRING_DATA_GEN_BODY(4)
176string GetQuery() override {
177 return "SELECT CONTAINS(s1, '') FROM strings";
178}
179string BenchmarkInfo() override {
180 return "STRING CONTAINS";
181}
182FINISH_BENCHMARK(StringContainsNull)
183//-----------------------------------------------------------------------------
184
185//------------------------- CONTAINS LIKE -------------------------------------
186DUCKDB_BENCHMARK(StringContainsLike, "[string]")
187STRING_DATA_GEN_BODY(4)
188string GetQuery() override {
189 return "SELECT s1 FROM strings WHERE s1 LIKE '%h%'";
190}
191string BenchmarkInfo() override {
192 return "STRING CONTAINS LIKE";
193}
194FINISH_BENCHMARK(StringContainsLike)
195//-----------------------------------------------------------------------------
196
197DUCKDB_BENCHMARK(StringRegex, "[string]")
198STRING_DATA_GEN_BODY(4)
199string GetQuery() override {
200 return "SELECT REGEXP_MATCHES(s1, 'h') FROM strings";
201}
202string BenchmarkInfo() override {
203 return "STRING REGEX";
204}
205FINISH_BENCHMARK(StringRegex)
206
207DUCKDB_BENCHMARK(StringRegexNull, "[string]")
208STRING_DATA_GEN_BODY(4)
209string GetQuery() override {
210 return "SELECT REGEXP_MATCHES(s1, '') FROM strings";
211}
212string BenchmarkInfo() override {
213 return "STRING REGEX";
214}
215FINISH_BENCHMARK(StringRegexNull)
216
217//----------------------- PREFIX benchmark ----------------------------------//
218DUCKDB_BENCHMARK(StringPrefix, "[string]")
219STRING_DATA_GEN_BODY(4)
220string GetQuery() override {
221 return "SELECT prefix(s1, 'a') FROM strings";
222}
223string BenchmarkInfo() override {
224 return "STRING PREFIX early out";
225}
226FINISH_BENCHMARK(StringPrefix)
227
228DUCKDB_BENCHMARK(StringPrefixInlined, "[string]")
229STRING_DATA_GEN_BODY(12)
230string GetQuery() override {
231 return "SELECT prefix(s1, 'a') FROM strings";
232}
233string BenchmarkInfo() override {
234 return "STRING PREFIX inlined";
235}
236FINISH_BENCHMARK(StringPrefixInlined)
237
238DUCKDB_BENCHMARK(StringPrefixPointer, "[string]")
239STRING_DATA_GEN_BODY(20)
240string GetQuery() override {
241 return "SELECT prefix(s1, 'a') FROM strings";
242}
243string BenchmarkInfo() override {
244 return "STRING PREFIX store pointer";
245}
246FINISH_BENCHMARK(StringPrefixPointer)
247
248//----------------------- PREFIX REGEX benchmark ----------------------------------//
249DUCKDB_BENCHMARK(StringPrefixRegEX, "[string]")
250STRING_DATA_GEN_BODY(4)
251string GetQuery() override {
252 return "SELECT REGEXP_MATCHES(s1, 'a%') FROM strings";
253}
254string BenchmarkInfo() override {
255 return "STRING PREFIX REGEX";
256}
257FINISH_BENCHMARK(StringPrefixRegEX)
258
259//----------------------- PREFIX LIKE benchmark ----------------------------------//
260DUCKDB_BENCHMARK(StringPrefixLike, "[string]")
261STRING_DATA_GEN_BODY(4)
262string GetQuery() override {
263 return "SELECT s1 FROM strings WHERE s1 LIKE 'a%'";
264}
265string BenchmarkInfo() override {
266 return "STRING PREFIX LIKE";
267}
268FINISH_BENCHMARK(StringPrefixLike)
269
270DUCKDB_BENCHMARK(StringPrefixInlinedLike, "[string]")
271STRING_DATA_GEN_BODY(12)
272string GetQuery() override {
273 return "SELECT s1 FROM strings WHERE s1 LIKE 'a%'";
274}
275string BenchmarkInfo() override {
276 return "STRING PREFIX inlined LIKE";
277}
278FINISH_BENCHMARK(StringPrefixInlinedLike)
279
280DUCKDB_BENCHMARK(StringPrefixPointerLike, "[string]")
281STRING_DATA_GEN_BODY(20)
282string GetQuery() override {
283 return "SELECT s1 FROM strings WHERE s1 LIKE 'a%'";
284}
285string BenchmarkInfo() override {
286 return "STRING PREFIX store pointer LIKE";
287}
288FINISH_BENCHMARK(StringPrefixPointerLike)
289
290//----------------------- SUFFIX benchmark ----------------------------------//
291DUCKDB_BENCHMARK(StringSuffixShort, "[string]")
292STRING_DATA_GEN_BODY(4)
293string GetQuery() override {
294 return "SELECT suffix(s1, 'a') FROM strings";
295}
296string BenchmarkInfo() override {
297 return "Short string for suffix";
298}
299FINISH_BENCHMARK(StringSuffixShort)
300
301DUCKDB_BENCHMARK(StringSuffixLong, "[string]")
302STRING_DATA_GEN_BODY(20)
303string GetQuery() override {
304 return "SELECT suffix(s1, 'a') FROM strings";
305}
306string BenchmarkInfo() override {
307 return "Long string for suffix";
308}
309FINISH_BENCHMARK(StringSuffixLong)
310
311//----------------------- SUFFIX REGEX benchmark ----------------------------------//
312DUCKDB_BENCHMARK(StringSuffixRegEX, "[string]")
313STRING_DATA_GEN_BODY(4)
314string GetQuery() override {
315 return "SELECT REGEXP_MATCHES(s1, '%a') FROM strings";
316}
317string BenchmarkInfo() override {
318 return "STRING suffix REGEX";
319}
320FINISH_BENCHMARK(StringSuffixRegEX)
321
322//----------------------- SUFFIX LIKE benchmark ----------------------------------//
323DUCKDB_BENCHMARK(StringSuffixLikeShort, "[string]")
324STRING_DATA_GEN_BODY(4)
325string GetQuery() override {
326 return "SELECT s1 FROM strings WHERE s1 LIKE '%a'";
327}
328string BenchmarkInfo() override {
329 return "Short string for suffix with LIKE";
330}
331FINISH_BENCHMARK(StringSuffixLikeShort)
332
333DUCKDB_BENCHMARK(StringSuffixLikeLong, "[string]")
334STRING_DATA_GEN_BODY(20)
335string GetQuery() override {
336 return "SELECT s1 FROM strings WHERE s1 LIKE '%a'";
337}
338string BenchmarkInfo() override {
339 return "Long string for suffix with LIKE";
340}
341FINISH_BENCHMARK(StringSuffixLikeLong)
342