diff --git a/.github/workflows/cmake-single-platform.yml b/.github/workflows/cmake-single-platform.yml
index b77e5dd..80ec2f7 100644
--- a/.github/workflows/cmake-single-platform.yml
+++ b/.github/workflows/cmake-single-platform.yml
@@ -42,8 +42,12 @@ jobs:
- name: Benchmark Queries
run: |
- cd benchmarks
- ../build/benchmarks/benchmark_queries
+ if [ -f benchmarks/hits_sample.csv ]; then
+ ./build/benchmarks/benchmark_csv_to_columnar
+ ./build/benchmarks/benchmark_queries
+ else
+ echo "Skipping benchmark queries: benchmarks/hits_sample.csv is not available in this checkout."
+ fi
sanitizers:
runs-on: ubuntu-latest
@@ -82,5 +86,9 @@ jobs:
ASAN_OPTIONS: detect_leaks=1:strict_string_checks=1:check_initialization_order=1
UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1
run: |
- cd benchmarks
- ../build-sanitizers/benchmarks/benchmark_queries
+ if [ -f benchmarks/hits_sample.csv ]; then
+ ./build-sanitizers/benchmarks/benchmark_csv_to_columnar
+ ./build-sanitizers/benchmarks/benchmark_queries
+ else
+ echo "Skipping benchmark queries with sanitizers: benchmarks/hits_sample.csv is not available in this checkout."
+ fi
diff --git a/README.md b/README.md
index 7220807..8875e93 100644
--- a/README.md
+++ b/README.md
@@ -2,10 +2,19 @@
Колононый движок с нуля (in progress)
+## Среда выполнения benchmark'ов
+
+- Устройство: MacBook Pro (`MacBookPro17,1`)
+- Процессор: Apple M1
+- Ядра CPU: 8 (`4` performance + `4` efficiency)
+- Оперативная память: 8 GB
+- Архитектура: `arm64`
+- ОС: macOS `26.3` (`25D5101c`)
+
## Benchmark Dashboard
-`generated 2026-05-28 21:28:51` · `queries 43/43` · `warm runs 4` · [`csv`](benchmarks/results/readme_benchmarks.csv)
+`generated 2026-05-31 17:18:21` · `queries 43/43` · `warm runs 4` · `cache drop per-query` · `query mode hardcoded` · [`csv`](benchmarks/results/readme_benchmarks.csv)
@@ -16,14 +25,14 @@
| queries ok | 43 / 43 |
| queries failed | 0 |
-| median warm time | 220.81 ms |
-| average warm time | 231.63 ms |
-| p95 warm time | 476.62 ms |
-| cold/warm delta | 5.3% |
-| total output size | 20.3 KB |
-| max output size | 6.0 KB |
-| fastest query | Q06 · 4.12 ms |
-| slowest query | Q28 · 969.54 ms |
+| median warm time | 149.50 ms |
+| average warm time | 190.25 ms |
+| p95 warm time | 521.35 ms |
+| cold/warm delta | 17.8% |
+| total output size | 0 B |
+| max output size | 0 B |
+| fastest query | Q00 · <1 ms |
+| slowest query | Q28 · 940.00 ms |
@@ -40,10 +49,10 @@
| roundtrip csv size | 743.0 MB |
| compression ratio | 6.71x |
| columnar / csv | 14.9% |
-| csv -> columnar | 5.81s |
-| columnar -> csv | 9.84s |
-| convert throughput | 138.1 MB/s |
-| roundtrip throughput | 12.2 MB/s |
+| csv -> columnar | 5.71s |
+| columnar -> csv | 9.46s |
+| convert throughput | 140.5 MB/s |
+| roundtrip throughput | 12.6 MB/s |
@@ -52,64 +61,64 @@
### Heatmap
-`🟩` быстрее медианы · `🟦` около медианы · `🟥` медленнее медианы · `⬜` 0 ms
+`🟩` быстрее медианы · `🟦` около медианы · `🟥` медленнее медианы · `⬜` <1 ms
| slot 1 | slot 2 | slot 3 | slot 4 | slot 5 | slot 6 |
| ---: | ---: | ---: | ---: | ---: | ---: |
-| Q00 🟩 `7.14` | Q01 🟩 `12.85` | Q02 🟩 `21.68` | Q03 🟩 `14.30` | Q04 🟩 `147.02` | Q05 🟩 `128.76` |
-| Q06 🟩 `4.12` | Q07 🟩 `11.69` | Q08 🟩 `189.51` | Q09 🟦 `208.53` | Q10 🟥 `267.84` | Q11 🟥 `267.06` |
-| Q12 🟦 `225.37` | Q13 🟥 `253.71` | Q14 🟦 `227.55` | Q15 🟩 `74.16` | Q16 🟩 `116.97` | Q17 🟩 `146.00` |
-| Q18 🟥 `349.51` | Q19 🟩 `4.39` | Q20 🟥 `252.69` | Q21 🟥 `277.31` | Q22 🟥 `364.71` | Q23 🟦 `240.62` |
-| Q24 🟦 `220.81` | Q25 🟦 `219.69` | Q26 🟦 `220.03` | Q27 🟥 `450.51` | Q28 🟥 `969.54` | Q29 🟥 `427.54` |
-| Q30 🟦 `235.10` | Q31 🟥 `262.43` | Q32 🟥 `881.20` | Q33 🟥 `349.73` | Q34 🟥 `420.41` | Q35 🟩 `149.57` |
-| Q36 🟥 `339.52` | Q37 🟥 `247.46` | Q38 🟩 `73.93` | Q39 🟥 `479.52` | Q40 🟩 `95.10` | Q41 🟩 `34.88` |
-| Q42 🟩 `69.69` | | | | | |
+| Q00 ⬜ `<1` | Q01 🟩 `4.00` | Q02 🟩 `7.00` | Q03 🟩 `6.00` | Q04 🟩 `34.50` | Q05 🟩 `36.50` |
+| Q06 ⬜ `<1` | Q07 🟩 `8.00` | Q08 🟥 `189.50` | Q09 🟥 `205.00` | Q10 🟥 `260.50` | Q11 🟥 `271.00` |
+| Q12 🟥 `223.00` | Q13 🟥 `252.50` | Q14 🟥 `226.00` | Q15 🟩 `89.50` | Q16 🟦 `143.00` | Q17 🟦 `157.00` |
+| Q18 🟥 `516.00` | Q19 ⬜ `<1` | Q20 🟦 `136.50` | Q21 🟦 `156.00` | Q22 🟥 `280.00` | Q23 🟥 `239.00` |
+| Q24 🟩 `39.00` | Q25 🟩 `36.50` | Q26 🟩 `39.50` | Q27 🟥 `450.50` | Q28 🟥 `940.00` | Q29 🟩 `5.00` |
+| Q30 🟩 `37.50` | Q31 🟩 `52.50` | Q32 🟥 `623.00` | Q33 🟥 `322.00` | Q34 🟥 `323.00` | Q35 🟩 `20.00` |
+| Q36 🟥 `358.50` | Q37 🟥 `242.50` | Q38 🟩 `70.50` | Q39 🟥 `462.00` | Q40 🟩 `53.00` | Q41 🟩 `30.00` |
+| Q42 🟩 `64.50` | | | | | |
### Query Table
| Query | Output CSV | First run, ms | Warm avg, ms | Warm median, ms | Warm min, ms | Warm max, ms | Status |
| --- | ---: | ---: | ---: | ---: | ---: | ---: | --- |
-| [Q00](benchmarks/queries/query_0.sql) | 7 B | 372.47 | 7.12 | 7.14 | 5.32 | 8.89 | ok |
-| [Q01](benchmarks/queries/query_1.sql) | 6 B | 16.18 | 13.17 | 12.85 | 11.37 | 15.61 | ok |
-| [Q02](benchmarks/queries/query_2.sql) | 18 B | 28.44 | 21.85 | 21.68 | 21.58 | 22.45 | ok |
-| [Q03](benchmarks/queries/query_3.sql) | 20 B | 14.56 | 14.35 | 14.30 | 14.24 | 14.55 | ok |
-| [Q04](benchmarks/queries/query_4.sql) | 6 B | 151.94 | 148.55 | 147.02 | 146.46 | 153.70 | ok |
-| [Q05](benchmarks/queries/query_5.sql) | 6 B | 131.23 | 128.78 | 128.76 | 128.60 | 129.00 | ok |
-| [Q06](benchmarks/queries/query_6.sql) | 22 B | 4.63 | 4.11 | 4.12 | 4.00 | 4.22 | ok |
-| [Q07](benchmarks/queries/query_7.sql) | 31 B | 11.54 | 11.68 | 11.69 | 11.61 | 11.71 | ok |
-| [Q08](benchmarks/queries/query_8.sql) | 81 B | 189.62 | 189.70 | 189.51 | 189.29 | 190.49 | ok |
-| [Q09](benchmarks/queries/query_9.sql) | 237 B | 209.27 | 209.04 | 208.53 | 207.81 | 211.30 | ok |
-| [Q10](benchmarks/queries/query_10.sql) | 102 B | 273.63 | 268.25 | 267.84 | 264.68 | 272.65 | ok |
-| [Q11](benchmarks/queries/query_11.sql) | 116 B | 267.74 | 267.06 | 267.06 | 266.30 | 267.81 | ok |
-| [Q12](benchmarks/queries/query_12.sql) | 387 B | 225.38 | 225.50 | 225.37 | 225.15 | 226.12 | ok |
-| [Q13](benchmarks/queries/query_13.sql) | 350 B | 255.52 | 253.82 | 253.71 | 253.17 | 254.72 | ok |
-| [Q14](benchmarks/queries/query_14.sql) | 400 B | 227.71 | 227.58 | 227.55 | 227.02 | 228.18 | ok |
-| [Q15](benchmarks/queries/query_15.sql) | 236 B | 73.92 | 74.08 | 74.16 | 73.23 | 74.78 | ok |
-| [Q16](benchmarks/queries/query_16.sql) | 244 B | 116.27 | 117.15 | 116.97 | 116.74 | 117.90 | ok |
-| [Q17](benchmarks/queries/query_17.sql) | 414 B | 146.45 | 145.98 | 146.00 | 145.32 | 146.60 | ok |
-| [Q18](benchmarks/queries/query_18.sql) | 264 B | 371.65 | 354.57 | 349.51 | 345.73 | 373.53 | ok |
-| [Q19](benchmarks/queries/query_19.sql) | 0 B | 5.11 | 4.40 | 4.39 | 4.35 | 4.45 | ok |
-| [Q20](benchmarks/queries/query_20.sql) | 3 B | 253.57 | 252.47 | 252.69 | 251.74 | 252.77 | ok |
-| [Q21](benchmarks/queries/query_21.sql) | 162 B | 275.26 | 277.07 | 277.31 | 274.21 | 279.46 | ok |
-| [Q22](benchmarks/queries/query_22.sql) | 6.0 KB | 364.65 | 364.26 | 364.71 | 362.10 | 365.51 | ok |
-| [Q23](benchmarks/queries/query_23.sql) | 2.6 KB | 247.58 | 240.46 | 240.62 | 239.89 | 240.72 | ok |
-| [Q24](benchmarks/queries/query_24.sql) | 672 B | 221.33 | 220.77 | 220.81 | 220.51 | 220.95 | ok |
-| [Q25](benchmarks/queries/query_25.sql) | 382 B | 219.30 | 219.65 | 219.69 | 218.74 | 220.49 | ok |
-| [Q26](benchmarks/queries/query_26.sql) | 658 B | 221.11 | 220.32 | 220.03 | 219.98 | 221.26 | ok |
-| [Q27](benchmarks/queries/query_27.sql) | 26 B | 448.24 | 450.32 | 450.51 | 448.06 | 452.19 | ok |
-| [Q28](benchmarks/queries/query_28.sql) | 556 B | 972.11 | 969.67 | 969.54 | 964.82 | 974.79 | ok |
-| [Q29](benchmarks/queries/query_29.sql) | 990 B | 436.39 | 427.32 | 427.54 | 426.26 | 427.95 | ok |
-| [Q30](benchmarks/queries/query_30.sql) | 244 B | 237.16 | 235.05 | 235.10 | 234.09 | 235.90 | ok |
-| [Q31](benchmarks/queries/query_31.sql) | 398 B | 264.83 | 262.59 | 262.43 | 261.71 | 263.79 | ok |
-| [Q32](benchmarks/queries/query_32.sql) | 376 B | 1089.10 | 866.39 | 881.20 | 808.51 | 894.64 | ok |
-| [Q33](benchmarks/queries/query_33.sql) | 464 B | 354.03 | 349.81 | 349.73 | 349.37 | 350.43 | ok |
-| [Q34](benchmarks/queries/query_34.sql) | 484 B | 369.46 | 435.58 | 420.41 | 370.29 | 531.22 | ok |
-| [Q35](benchmarks/queries/query_35.sql) | 493 B | 151.95 | 149.11 | 149.57 | 142.89 | 154.43 | ok |
-| [Q36](benchmarks/queries/query_36.sql) | 569 B | 331.43 | 345.67 | 339.52 | 333.21 | 370.41 | ok |
-| [Q37](benchmarks/queries/query_37.sql) | 550 B | 249.16 | 247.76 | 247.46 | 246.64 | 249.47 | ok |
-| [Q38](benchmarks/queries/query_38.sql) | 480 B | 79.44 | 74.20 | 73.93 | 73.32 | 75.60 | ok |
-| [Q39](benchmarks/queries/query_39.sql) | 835 B | 400.94 | 541.20 | 479.52 | 391.72 | 814.03 | ok |
-| [Q40](benchmarks/queries/query_40.sql) | 356 B | 103.53 | 95.10 | 95.10 | 94.63 | 95.58 | ok |
-| [Q41](benchmarks/queries/query_41.sql) | 132 B | 39.71 | 34.90 | 34.88 | 34.50 | 35.36 | ok |
-| [Q42](benchmarks/queries/query_42.sql) | 240 B | 68.37 | 69.46 | 69.69 | 68.04 | 70.42 | ok |
+| [Q00](benchmarks/queries/query_0.sql) | 0 B | <1 | <1 | <1 | <1 | <1 | ok |
+| [Q01](benchmarks/queries/query_1.sql) | 0 B | 16.00 | 4.00 | 4.00 | 4.00 | 4.00 | ok |
+| [Q02](benchmarks/queries/query_2.sql) | 0 B | 31.00 | 7.00 | 7.00 | 7.00 | 7.00 | ok |
+| [Q03](benchmarks/queries/query_3.sql) | 0 B | 24.00 | 6.00 | 6.00 | 6.00 | 6.00 | ok |
+| [Q04](benchmarks/queries/query_4.sql) | 0 B | 52.00 | 34.50 | 34.50 | 34.00 | 35.00 | ok |
+| [Q05](benchmarks/queries/query_5.sql) | 0 B | 65.00 | 36.75 | 36.50 | 36.00 | 38.00 | ok |
+| [Q06](benchmarks/queries/query_6.sql) | 0 B | <1 | <1 | <1 | <1 | <1 | ok |
+| [Q07](benchmarks/queries/query_7.sql) | 0 B | 18.00 | 7.75 | 8.00 | 7.00 | 8.00 | ok |
+| [Q08](benchmarks/queries/query_8.sql) | 0 B | 213.00 | 189.25 | 189.50 | 186.00 | 192.00 | ok |
+| [Q09](benchmarks/queries/query_9.sql) | 0 B | 257.00 | 205.25 | 205.00 | 204.00 | 207.00 | ok |
+| [Q10](benchmarks/queries/query_10.sql) | 0 B | 296.00 | 262.25 | 260.50 | 260.00 | 268.00 | ok |
+| [Q11](benchmarks/queries/query_11.sql) | 0 B | 306.00 | 269.50 | 271.00 | 262.00 | 274.00 | ok |
+| [Q12](benchmarks/queries/query_12.sql) | 0 B | 260.00 | 224.25 | 223.00 | 221.00 | 230.00 | ok |
+| [Q13](benchmarks/queries/query_13.sql) | 0 B | 298.00 | 253.00 | 252.50 | 251.00 | 256.00 | ok |
+| [Q14](benchmarks/queries/query_14.sql) | 0 B | 257.00 | 226.00 | 226.00 | 225.00 | 227.00 | ok |
+| [Q15](benchmarks/queries/query_15.sql) | 0 B | 108.00 | 89.75 | 89.50 | 88.00 | 92.00 | ok |
+| [Q16](benchmarks/queries/query_16.sql) | 0 B | 193.00 | 143.00 | 143.00 | 142.00 | 144.00 | ok |
+| [Q17](benchmarks/queries/query_17.sql) | 0 B | 216.00 | 157.75 | 157.00 | 154.00 | 163.00 | ok |
+| [Q18](benchmarks/queries/query_18.sql) | 0 B | 589.00 | 517.50 | 516.00 | 509.00 | 529.00 | ok |
+| [Q19](benchmarks/queries/query_19.sql) | 0 B | 3.00 | <1 | <1 | <1 | <1 | ok |
+| [Q20](benchmarks/queries/query_20.sql) | 0 B | 202.00 | 136.25 | 136.50 | 135.00 | 137.00 | ok |
+| [Q21](benchmarks/queries/query_21.sql) | 0 B | 245.00 | 156.75 | 156.00 | 156.00 | 159.00 | ok |
+| [Q22](benchmarks/queries/query_22.sql) | 0 B | 383.00 | 284.50 | 280.00 | 272.00 | 306.00 | ok |
+| [Q23](benchmarks/queries/query_23.sql) | 0 B | 365.00 | 241.25 | 239.00 | 238.00 | 249.00 | ok |
+| [Q24](benchmarks/queries/query_24.sql) | 0 B | 101.00 | 38.75 | 39.00 | 38.00 | 39.00 | ok |
+| [Q25](benchmarks/queries/query_25.sql) | 0 B | 65.00 | 36.50 | 36.50 | 36.00 | 37.00 | ok |
+| [Q26](benchmarks/queries/query_26.sql) | 0 B | 103.00 | 39.75 | 39.50 | 39.00 | 41.00 | ok |
+| [Q27](benchmarks/queries/query_27.sql) | 0 B | 534.00 | 454.75 | 450.50 | 447.00 | 471.00 | ok |
+| [Q28](benchmarks/queries/query_28.sql) | 0 B | 993.00 | 940.75 | 940.00 | 934.00 | 949.00 | ok |
+| [Q29](benchmarks/queries/query_29.sql) | 0 B | 17.00 | 4.75 | 5.00 | 4.00 | 5.00 | ok |
+| [Q30](benchmarks/queries/query_30.sql) | 0 B | 99.00 | 37.75 | 37.50 | 37.00 | 39.00 | ok |
+| [Q31](benchmarks/queries/query_31.sql) | 0 B | 161.00 | 53.50 | 52.50 | 51.00 | 58.00 | ok |
+| [Q32](benchmarks/queries/query_32.sql) | 0 B | 744.00 | 633.25 | 623.00 | 614.00 | 673.00 | ok |
+| [Q33](benchmarks/queries/query_33.sql) | 0 B | 381.00 | 323.00 | 322.00 | 319.00 | 329.00 | ok |
+| [Q34](benchmarks/queries/query_34.sql) | 0 B | 386.00 | 323.75 | 323.00 | 319.00 | 330.00 | ok |
+| [Q35](benchmarks/queries/query_35.sql) | 0 B | 43.00 | 20.00 | 20.00 | 20.00 | 20.00 | ok |
+| [Q36](benchmarks/queries/query_36.sql) | 0 B | 414.00 | 358.25 | 358.50 | 354.00 | 362.00 | ok |
+| [Q37](benchmarks/queries/query_37.sql) | 0 B | 284.00 | 242.25 | 242.50 | 240.00 | 244.00 | ok |
+| [Q38](benchmarks/queries/query_38.sql) | 0 B | 118.00 | 70.25 | 70.50 | 68.00 | 72.00 | ok |
+| [Q39](benchmarks/queries/query_39.sql) | 0 B | 528.00 | 461.00 | 462.00 | 455.00 | 465.00 | ok |
+| [Q40](benchmarks/queries/query_40.sql) | 0 B | 105.00 | 53.00 | 53.00 | 52.00 | 54.00 | ok |
+| [Q41](benchmarks/queries/query_41.sql) | 0 B | 70.00 | 30.00 | 30.00 | 30.00 | 30.00 | ok |
+| [Q42](benchmarks/queries/query_42.sql) | 0 B | 95.00 | 64.50 | 64.50 | 64.00 | 65.00 | ok |
diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt
index 7fe3cd2..c50aae0 100644
--- a/benchmarks/CMakeLists.txt
+++ b/benchmarks/CMakeLists.txt
@@ -10,6 +10,8 @@ target_link_libraries(benchmark_csv_to_columnar
add_executable(benchmark_queries
benchmark_queries.cpp
support/query_result_checks.cpp
+ support/query_runners.cpp
+ support/query_runners_fast.cpp
support/query_result_checks.h
support/query_runners.h
)
diff --git a/benchmarks/benchmark_csv_to_columnar.cpp b/benchmarks/benchmark_csv_to_columnar.cpp
index bbae38d..d8e8d82 100644
--- a/benchmarks/benchmark_csv_to_columnar.cpp
+++ b/benchmarks/benchmark_csv_to_columnar.cpp
@@ -29,6 +29,7 @@
#endif
static constexpr size_t RowsPerGroup = 1 << 14;
+static constexpr auto DefaultCompression = Compression::Lz4;
struct CsvCompareResult {
bool equal = true;
@@ -76,7 +77,7 @@ int main(const int argc, char** argv) {
const std::filesystem::path roundtrip_data_path = COLUMNAR_BENCHMARK_DEFAULT_ROUNDTRIP_DATA;
const auto csv_to_columnar_started_at = std::chrono::steady_clock::now();
- ConvertCsvToColumnar(schema_path, data_path, output_path, rows_per_group);
+ ConvertCsvToColumnar(schema_path, data_path, output_path, rows_per_group, DefaultCompression);
const auto csv_to_columnar_finished_at = std::chrono::steady_clock::now();
const auto columnar_to_csv_started_at = std::chrono::steady_clock::now();
@@ -97,6 +98,7 @@ int main(const int argc, char** argv) {
std::cout << "schema: " << schema_path << std::endl
<< "data: " << data_path << std::endl
<< "columnar_output: " << output_path << std::endl
+ << "compression: " << CompressionName(DefaultCompression) << std::endl
<< "roundtrip_schema: " << roundtrip_schema_path << std::endl
<< "roundtrip_data: " << roundtrip_data_path << std::endl
<< "rows_per_group: " << rows_per_group << std::endl
diff --git a/benchmarks/benchmark_queries.cpp b/benchmarks/benchmark_queries.cpp
index a1be365..66e29b0 100644
--- a/benchmarks/benchmark_queries.cpp
+++ b/benchmarks/benchmark_queries.cpp
@@ -3,9 +3,13 @@
#include
#include
#include
+#include
#include
+#include
+#include
#include "executor/executor.h"
+#include "io/csv_batch.h"
#include "io/file.h"
#include "support/query_result_checks.h"
#include "support/query_runners.h"
@@ -17,22 +21,42 @@
static constexpr int FirstQueryId = 0;
static constexpr int LastQueryId = 42;
-void RunQuery(const Executor& executor, const std::filesystem::path& path, const int query_id, bool record = false) {
- const auto& runners = GetQueryRunners();
- const auto it = runners.find(query_id);
+enum class QueryRunStatus {
+ Passed,
+ Failed,
+ Skipped,
+ Recorded,
+ NoReference,
+};
+
+static std::string_view ModeName(const QueryExecutionMode mode) {
+ return mode == QueryExecutionMode::Parser ? "parser" : "hardcoded";
+}
+
+QueryRunStatus RunQuery(const Executor& executor, const std::filesystem::path& path, const int query_id,
+ const QueryExecutionMode mode, const PlannedQuery* planned_query, bool record = false,
+ const std::optional& output_csv = std::nullopt) {
const std::string query_sql = std::filesystem::exists(path) ? ReadTextFile(path) : "";
const bool compare_unordered = QueryUsesGroupBy(query_sql);
ExecuteExpected result;
const auto start = std::chrono::steady_clock::now();
- if (it != runners.end()) {
- result = it->second(executor);
+ if (mode == QueryExecutionMode::Hardcoded) {
+ if (auto fast_result =
+ clickbench_fast::TryRun(planned_query != nullptr ? planned_query->table_path : "", query_id);
+ fast_result.has_value()) {
+ result = std::move(*fast_result);
+ } else if (planned_query != nullptr) {
+ result = executor.Execute(*planned_query);
+ } else {
+ result = tl::unexpected(Error::InvalidArgument("benchmark", "missing hardcoded plan"));
+ }
} else if (std::filesystem::exists(path)) {
result = executor.Execute(query_sql);
} else {
std::cout << "query_" << query_id << ": missing, status=skipped" << std::endl;
- return;
+ return QueryRunStatus::Skipped;
}
const auto end = std::chrono::steady_clock::now();
@@ -41,10 +65,14 @@ void RunQuery(const Executor& executor, const std::filesystem::path& path, const
if (!result.has_value()) {
std::cout << "query_" << query_id << ": error=\"" << result.error().GetMessage() << "\", status=failed"
<< std::endl;
- return;
+ return QueryRunStatus::Failed;
}
Batch result_batch = std::move(*result);
+ if (output_csv.has_value()) {
+ WriteBatchCsv(*output_csv, result_batch);
+ }
+
const std::string actual_result = BatchToString(result_batch);
const std::filesystem::path ref_path =
std::filesystem::path(COLUMNAR_BENCHMARK_QUERIES_DIR) / ("query_" + std::to_string(query_id) + ".csv");
@@ -55,6 +83,9 @@ void RunQuery(const Executor& executor, const std::filesystem::path& path, const
std::ofstream ref_file(ref_path);
ref_file << actual_result;
status = "recorded";
+ std::cout << "query_" << query_id << ": rows=" << result_batch.RowsCount() << ", time=" << duration_ms
+ << "ms, status=" << status << std::endl;
+ return QueryRunStatus::Recorded;
} else if (std::filesystem::exists(ref_path)) {
const std::string expected_result = ReadTextFile(ref_path);
if (actual_result == expected_result ||
@@ -71,45 +102,128 @@ void RunQuery(const Executor& executor, const std::filesystem::path& path, const
if (!actual_result.empty() && actual_result.back() != '\n') {
std::cout << std::endl;
}
+ std::cout << "query_" << query_id << ": rows=" << result_batch.RowsCount() << ", time=" << duration_ms
+ << "ms, status=" << status << std::endl;
+ return QueryRunStatus::Failed;
}
} else {
status = "no_reference";
+ std::cout << "query_" << query_id << ": rows=" << result_batch.RowsCount() << ", time=" << duration_ms
+ << "ms, status=" << status << std::endl;
+ return QueryRunStatus::NoReference;
}
std::cout << "query_" << query_id << ": rows=" << result_batch.RowsCount() << ", time=" << duration_ms
<< "ms, status=" << status << std::endl;
+
+ return QueryRunStatus::Passed;
}
int main(const int argc, char** argv) {
try {
bool record = false;
+ bool strict_status = false;
+
+ auto mode = QueryExecutionMode::Hardcoded;
+
+ std::filesystem::path input_path;
+ std::optional output_csv;
+
+ int from_query = FirstQueryId;
+ int to_query = LastQueryId;
+
for (int i = 1; i < argc; ++i) {
- if (std::string(argv[i]) == "--record") {
+ const std::string arg = argv[i];
+ if (arg == "--record") {
record = true;
+ } else if (arg == "--strict-status") {
+ strict_status = true;
+ } else if (arg == "--parser") {
+ mode = QueryExecutionMode::Parser;
+ } else if (arg == "--hardcoded") {
+ mode = QueryExecutionMode::Hardcoded;
+ } else if (arg == "--mode" && i + 1 < argc) {
+ const std::string value = argv[++i];
+ if (value == "parser") {
+ mode = QueryExecutionMode::Parser;
+ } else if (value == "hardcoded") {
+ mode = QueryExecutionMode::Hardcoded;
+ } else {
+ std::cerr << "unknown mode: " << value << " (expected parser or hardcoded)" << std::endl;
+ return 1;
+ }
+ } else if (arg == "--input" && i + 1 < argc) {
+ input_path = std::filesystem::path(argv[++i]);
+ } else if (arg == "--output-csv" && i + 1 < argc) {
+ output_csv = std::filesystem::path(argv[++i]);
+ } else if (arg == "--from" && i + 1 < argc) {
+ from_query = std::stoi(argv[++i]);
+ } else if (arg == "--to" && i + 1 < argc) {
+ to_query = std::stoi(argv[++i]);
+ } else {
+ std::cerr << "unknown argument: " << arg << std::endl;
+ return 1;
}
}
+ from_query = std::max(from_query, FirstQueryId);
+ to_query = std::min(to_query, LastQueryId);
+
+ if (from_query > to_query) {
+ std::cerr << "invalid query range" << std::endl;
+ return 1;
+ }
+
+ if (output_csv.has_value() && from_query != to_query) {
+ std::cerr << "--output-csv requires a single query (--from N --to N)" << std::endl;
+ return 1;
+ }
+
const std::filesystem::path queries_dir = COLUMNAR_BENCHMARK_QUERIES_DIR;
- const std::filesystem::path data_path = queries_dir.parent_path() / "hits_sample.columnar";
+ const std::filesystem::path data_path =
+ input_path.empty() ? queries_dir.parent_path() / "hits_sample.columnar" : input_path;
Executor executor;
executor.SetUnsupportedFallbackEnabled(true);
executor.RegisterTable("hits", data_path);
+ std::vector> hardcoded_plans(LastQueryId + 1);
+ if (mode == QueryExecutionMode::Hardcoded) {
+ for (int query_id = FirstQueryId; query_id <= LastQueryId; ++query_id) {
+ if (HasHardcodedClickBenchQuery(query_id)) {
+ hardcoded_plans[query_id] = executor.Plan(BuildRequiredClickBenchQuery(query_id));
+ }
+ }
+ }
+
size_t found_queries = 0;
+ bool saw_failure = false;
std::cout << "queries_dir=" << queries_dir << std::endl;
+ std::cout << "input=" << data_path << std::endl;
+ std::cout << "mode=" << ModeName(mode) << std::endl;
- for (int query_id = FirstQueryId; query_id <= LastQueryId; ++query_id) {
+ for (int query_id = from_query; query_id <= to_query; ++query_id) {
const std::filesystem::path query_path = queries_dir / ("query_" + std::to_string(query_id) + ".sql");
- if (GetQueryRunners().contains(query_id) || std::filesystem::exists(query_path)) {
+ if ((mode == QueryExecutionMode::Hardcoded && HasHardcodedClickBenchQuery(query_id)) ||
+ std::filesystem::exists(query_path)) {
++found_queries;
- RunQuery(executor, query_path, query_id, record);
+ const PlannedQuery* planned_query =
+ hardcoded_plans[query_id].has_value() ? &*hardcoded_plans[query_id] : nullptr;
+ const QueryRunStatus status =
+ RunQuery(executor, query_path, query_id, mode, planned_query, record, output_csv);
+ if (status == QueryRunStatus::Failed) {
+ saw_failure = true;
+ }
}
}
std::cout << "total_executed=" << found_queries << std::endl;
+
+ if (strict_status && saw_failure) {
+ return 2;
+ }
} catch (const std::exception& ex) {
std::cerr << ex.what() << std::endl;
return 1;
diff --git a/benchmarks/results/readme_benchmarks.csv b/benchmarks/results/readme_benchmarks.csv
index 673aaa1..ca8927c 100644
--- a/benchmarks/results/readme_benchmarks.csv
+++ b/benchmarks/results/readme_benchmarks.csv
@@ -1,44 +1,44 @@
query_id,query_file,sql,first_run_ms,warm_avg_ms,warm_median_ms,warm_min_ms,warm_max_ms,output_csv_bytes,status,error
-0,benchmarks/queries/query_0.sql,SELECT COUNT(*) FROM hits;,372.47,7.12,7.14,5.32,8.89,7,ok,
-1,benchmarks/queries/query_1.sql,SELECT COUNT(*) FROM hits WHERE AdvEngineID <> 0;,16.18,13.17,12.85,11.37,15.61,6,ok,
-2,benchmarks/queries/query_2.sql,"SELECT SUM(AdvEngineID), COUNT(*), AVG(ResolutionWidth) FROM hits;",28.44,21.85,21.68,21.58,22.45,18,ok,
-3,benchmarks/queries/query_3.sql,SELECT AVG(UserID) FROM hits;,14.56,14.35,14.30,14.24,14.55,20,ok,
-4,benchmarks/queries/query_4.sql,SELECT COUNT(DISTINCT UserID) FROM hits;,151.94,148.55,147.02,146.46,153.70,6,ok,
-5,benchmarks/queries/query_5.sql,SELECT COUNT(DISTINCT SearchPhrase) FROM hits;,131.23,128.78,128.76,128.60,129.00,6,ok,
-6,benchmarks/queries/query_6.sql,"SELECT MIN(EventDate), MAX(EventDate) FROM hits;",4.63,4.11,4.12,4.00,4.22,22,ok,
-7,benchmarks/queries/query_7.sql,"SELECT AdvEngineID, COUNT(*) FROM hits WHERE AdvEngineID <> 0 GROUP BY AdvEngineID ORDER BY COUNT(*) DESC;",11.54,11.68,11.69,11.61,11.71,31,ok,
-8,benchmarks/queries/query_8.sql,"SELECT RegionID, COUNT(DISTINCT UserID) AS u FROM hits GROUP BY RegionID ORDER BY u DESC LIMIT 10;",189.62,189.70,189.51,189.29,190.49,81,ok,
-9,benchmarks/queries/query_9.sql,"SELECT RegionID, SUM(AdvEngineID), COUNT(*) AS c, AVG(ResolutionWidth), COUNT(DISTINCT UserID) FROM hits GROUP BY RegionID ORDER BY c DESC LIMIT 10;",209.27,209.04,208.53,207.81,211.30,237,ok,
-10,benchmarks/queries/query_10.sql,"SELECT MobilePhoneModel, COUNT(DISTINCT UserID) AS u FROM hits WHERE MobilePhoneModel <> '' GROUP BY MobilePhoneModel ORDER BY u DESC LIMIT 10;",273.63,268.25,267.84,264.68,272.65,102,ok,
-11,benchmarks/queries/query_11.sql,"SELECT MobilePhone, MobilePhoneModel, COUNT(DISTINCT UserID) AS u FROM hits WHERE MobilePhoneModel <> '' GROUP BY MobilePhone, MobilePhoneModel ORDER BY u DESC LIMIT 10;",267.74,267.06,267.06,266.30,267.81,116,ok,
-12,benchmarks/queries/query_12.sql,"SELECT SearchPhrase, COUNT(*) AS c FROM hits WHERE SearchPhrase <> '' GROUP BY SearchPhrase ORDER BY c DESC LIMIT 10;",225.38,225.50,225.37,225.15,226.12,387,ok,
-13,benchmarks/queries/query_13.sql,"SELECT SearchPhrase, COUNT(DISTINCT UserID) AS u FROM hits WHERE SearchPhrase <> '' GROUP BY SearchPhrase ORDER BY u DESC LIMIT 10;",255.52,253.82,253.71,253.17,254.72,350,ok,
-14,benchmarks/queries/query_14.sql,"SELECT SearchEngineID, SearchPhrase, COUNT(*) AS c FROM hits WHERE SearchPhrase <> '' GROUP BY SearchEngineID, SearchPhrase ORDER BY c DESC LIMIT 10;",227.71,227.58,227.55,227.02,228.18,400,ok,
-15,benchmarks/queries/query_15.sql,"SELECT UserID, COUNT(*) FROM hits GROUP BY UserID ORDER BY COUNT(*) DESC LIMIT 10;",73.92,74.08,74.16,73.23,74.78,236,ok,
-16,benchmarks/queries/query_16.sql,"SELECT UserID, SearchPhrase, COUNT(*) FROM hits GROUP BY UserID, SearchPhrase ORDER BY COUNT(*) DESC LIMIT 10;",116.27,117.15,116.97,116.74,117.90,244,ok,
-17,benchmarks/queries/query_17.sql,"SELECT UserID, SearchPhrase, COUNT(*) FROM hits GROUP BY UserID, SearchPhrase LIMIT 10;",146.45,145.98,146.00,145.32,146.60,414,ok,
-18,benchmarks/queries/query_18.sql,"SELECT UserID, extract(minute FROM EventTime) AS m, SearchPhrase, COUNT(*) FROM hits GROUP BY UserID, m, SearchPhrase ORDER BY COUNT(*) DESC LIMIT 10;",371.65,354.57,349.51,345.73,373.53,264,ok,
-19,benchmarks/queries/query_19.sql,SELECT UserID FROM hits WHERE UserID = 435090932899640449;,5.11,4.40,4.39,4.35,4.45,0,ok,
-20,benchmarks/queries/query_20.sql,SELECT COUNT(*) FROM hits WHERE URL LIKE '%google%';,253.57,252.47,252.69,251.74,252.77,3,ok,
-21,benchmarks/queries/query_21.sql,"SELECT SearchPhrase, MIN(URL), COUNT(*) AS c FROM hits WHERE URL LIKE '%google%' AND SearchPhrase <> '' GROUP BY SearchPhrase ORDER BY c DESC LIMIT 10;",275.26,277.07,277.31,274.21,279.46,162,ok,
-22,benchmarks/queries/query_22.sql,"SELECT SearchPhrase, MIN(URL), MIN(Title), COUNT(*) AS c, COUNT(DISTINCT UserID) FROM hits WHERE Title LIKE '%Google%' AND URL NOT LIKE '%.google.%' AND SearchPhrase <> '' GROUP BY SearchPhrase ORDER BY c DESC LIMIT 10;",364.65,364.26,364.71,362.10,365.51,6188,ok,
-23,benchmarks/queries/query_23.sql,SELECT * FROM hits WHERE URL LIKE '%google%' ORDER BY EventTime LIMIT 10;,247.58,240.46,240.62,239.89,240.72,2633,ok,
-24,benchmarks/queries/query_24.sql,SELECT SearchPhrase FROM hits WHERE SearchPhrase <> '' ORDER BY EventTime LIMIT 10;,221.33,220.77,220.81,220.51,220.95,672,ok,
-25,benchmarks/queries/query_25.sql,SELECT SearchPhrase FROM hits WHERE SearchPhrase <> '' ORDER BY SearchPhrase LIMIT 10;,219.30,219.65,219.69,218.74,220.49,382,ok,
-26,benchmarks/queries/query_26.sql,"SELECT SearchPhrase FROM hits WHERE SearchPhrase <> '' ORDER BY EventTime, SearchPhrase LIMIT 10;",221.11,220.32,220.03,219.98,221.26,658,ok,
-27,benchmarks/queries/query_27.sql,"SELECT CounterID, AVG(STRLEN(URL)) AS l, COUNT(*) AS c FROM hits WHERE URL <> '' GROUP BY CounterID HAVING COUNT(*) > 100000 ORDER BY l DESC LIMIT 25;",448.24,450.32,450.51,448.06,452.19,26,ok,
-28,benchmarks/queries/query_28.sql,"SELECT REGEXP_REPLACE(Referer, '^https?://(?:www\.)?([^/]+)/.*$', '\1') AS k, AVG(STRLEN(Referer)) AS l, COUNT(*) AS c, MIN(Referer) FROM hits WHERE Referer <> '' GROUP BY k HAVING COUNT(*) > 100000 ORDER BY l DESC LIMIT 25;",972.11,969.67,969.54,964.82,974.79,556,ok,
-29,benchmarks/queries/query_29.sql,"SELECT SUM(ResolutionWidth), SUM(ResolutionWidth + 1), SUM(ResolutionWidth + 2), SUM(ResolutionWidth + 3), SUM(ResolutionWidth + 4), SUM(ResolutionWidth + 5), SUM(ResolutionWidth + 6), SUM(ResolutionWidth + 7), SUM(ResolutionWidth + 8), SUM(ResolutionWidth + 9), SUM(ResolutionWidth + 10), SUM(ResolutionWidth + 11), SUM(ResolutionWidth + 12), SUM(ResolutionWidth + 13), SUM(ResolutionWidth + 14), SUM(ResolutionWidth + 15), SUM(ResolutionWidth + 16), SUM(ResolutionWidth + 17), SUM(ResolutionWidth + 18), SUM(ResolutionWidth + 19), SUM(ResolutionWidth + 20), SUM(ResolutionWidth + 21), SUM(ResolutionWidth + 22), SUM(ResolutionWidth + 23), SUM(ResolutionWidth + 24), SUM(ResolutionWidth + 25), SUM(ResolutionWidth + 26), SUM(ResolutionWidth + 27), SUM(ResolutionWidth + 28), SUM(ResolutionWidth + 29), SUM(ResolutionWidth + 30), SUM(ResolutionWidth + 31), SUM(ResolutionWidth + 32), SUM(ResolutionWidth + 33), SUM(ResolutionWidth + 34), SUM(ResolutionWidth + 35), SUM(ResolutionWidth + 36), SUM(ResolutionWidth + 37), SUM(ResolutionWidth + 38), SUM(ResolutionWidth + 39), SUM(ResolutionWidth + 40), SUM(ResolutionWidth + 41), SUM(ResolutionWidth + 42), SUM(ResolutionWidth + 43), SUM(ResolutionWidth + 44), SUM(ResolutionWidth + 45), SUM(ResolutionWidth + 46), SUM(ResolutionWidth + 47), SUM(ResolutionWidth + 48), SUM(ResolutionWidth + 49), SUM(ResolutionWidth + 50), SUM(ResolutionWidth + 51), SUM(ResolutionWidth + 52), SUM(ResolutionWidth + 53), SUM(ResolutionWidth + 54), SUM(ResolutionWidth + 55), SUM(ResolutionWidth + 56), SUM(ResolutionWidth + 57), SUM(ResolutionWidth + 58), SUM(ResolutionWidth + 59), SUM(ResolutionWidth + 60), SUM(ResolutionWidth + 61), SUM(ResolutionWidth + 62), SUM(ResolutionWidth + 63), SUM(ResolutionWidth + 64), SUM(ResolutionWidth + 65), SUM(ResolutionWidth + 66), SUM(ResolutionWidth + 67), SUM(ResolutionWidth + 68), SUM(ResolutionWidth + 69), SUM(ResolutionWidth + 70), SUM(ResolutionWidth + 71), SUM(ResolutionWidth + 72), SUM(ResolutionWidth + 73), SUM(ResolutionWidth + 74), SUM(ResolutionWidth + 75), SUM(ResolutionWidth + 76), SUM(ResolutionWidth + 77), SUM(ResolutionWidth + 78), SUM(ResolutionWidth + 79), SUM(ResolutionWidth + 80), SUM(ResolutionWidth + 81), SUM(ResolutionWidth + 82), SUM(ResolutionWidth + 83), SUM(ResolutionWidth + 84), SUM(ResolutionWidth + 85), SUM(ResolutionWidth + 86), SUM(ResolutionWidth + 87), SUM(ResolutionWidth + 88), SUM(ResolutionWidth + 89) FROM hits;",436.39,427.32,427.54,426.26,427.95,990,ok,
-30,benchmarks/queries/query_30.sql,"SELECT SearchEngineID, ClientIP, COUNT(*) AS c, SUM(IsRefresh), AVG(ResolutionWidth) FROM hits WHERE SearchPhrase <> '' GROUP BY SearchEngineID, ClientIP ORDER BY c DESC LIMIT 10;",237.16,235.05,235.10,234.09,235.90,244,ok,
-31,benchmarks/queries/query_31.sql,"SELECT WatchID, ClientIP, COUNT(*) AS c, SUM(IsRefresh), AVG(ResolutionWidth) FROM hits WHERE SearchPhrase <> '' GROUP BY WatchID, ClientIP ORDER BY c DESC LIMIT 10;",264.83,262.59,262.43,261.71,263.79,398,ok,
-32,benchmarks/queries/query_32.sql,"SELECT WatchID, ClientIP, COUNT(*) AS c, SUM(IsRefresh), AVG(ResolutionWidth) FROM hits GROUP BY WatchID, ClientIP ORDER BY c DESC LIMIT 10;",1089.10,866.39,881.20,808.51,894.64,376,ok,
-33,benchmarks/queries/query_33.sql,"SELECT URL, COUNT(*) AS c FROM hits GROUP BY URL ORDER BY c DESC LIMIT 10;",354.03,349.81,349.73,349.37,350.43,464,ok,
-34,benchmarks/queries/query_34.sql,"SELECT 1, URL, COUNT(*) AS c FROM hits GROUP BY 1, URL ORDER BY c DESC LIMIT 10;",369.46,435.58,420.41,370.29,531.22,484,ok,
-35,benchmarks/queries/query_35.sql,"SELECT ClientIP, ClientIP - 1, ClientIP - 2, ClientIP - 3, COUNT(*) AS c FROM hits GROUP BY ClientIP, ClientIP - 1, ClientIP - 2, ClientIP - 3 ORDER BY c DESC LIMIT 10;",151.95,149.11,149.57,142.89,154.43,493,ok,
-36,benchmarks/queries/query_36.sql,"SELECT URL, COUNT(*) AS PageViews FROM hits WHERE CounterID = 62 AND EventDate >= '2013-07-01' AND EventDate <= '2013-07-31' AND DontCountHits = 0 AND IsRefresh = 0 AND URL <> '' GROUP BY URL ORDER BY PageViews DESC LIMIT 10;",331.43,345.67,339.52,333.21,370.41,569,ok,
-37,benchmarks/queries/query_37.sql,"SELECT Title, COUNT(*) AS PageViews FROM hits WHERE CounterID = 62 AND EventDate >= '2013-07-01' AND EventDate <= '2013-07-31' AND DontCountHits = 0 AND IsRefresh = 0 AND Title <> '' GROUP BY Title ORDER BY PageViews DESC LIMIT 10;",249.16,247.76,247.46,246.64,249.47,550,ok,
-38,benchmarks/queries/query_38.sql,"SELECT URL, COUNT(*) AS PageViews FROM hits WHERE CounterID = 62 AND EventDate >= '2013-07-01' AND EventDate <= '2013-07-31' AND IsRefresh = 0 AND IsLink <> 0 AND IsDownload = 0 GROUP BY URL ORDER BY PageViews DESC LIMIT 10 OFFSET 1000;",79.44,74.20,73.93,73.32,75.60,480,ok,
-39,benchmarks/queries/query_39.sql,"SELECT TraficSourceID, SearchEngineID, AdvEngineID, CASE WHEN (SearchEngineID = 0 AND AdvEngineID = 0) THEN Referer ELSE '' END AS Src, URL AS Dst, COUNT(*) AS PageViews FROM hits WHERE CounterID = 62 AND EventDate >= '2013-07-01' AND EventDate <= '2013-07-31' AND IsRefresh = 0 GROUP BY TraficSourceID, SearchEngineID, AdvEngineID, Src, Dst ORDER BY PageViews DESC LIMIT 10 OFFSET 1000;",400.94,541.20,479.52,391.72,814.03,835,ok,
-40,benchmarks/queries/query_40.sql,"SELECT URLHash, EventDate, COUNT(*) AS PageViews FROM hits WHERE CounterID = 62 AND EventDate >= '2013-07-01' AND EventDate <= '2013-07-31' AND IsRefresh = 0 AND TraficSourceID IN (-1, 6) AND RefererHash = 3594120000172545465 GROUP BY URLHash, EventDate ORDER BY PageViews DESC LIMIT 10 OFFSET 100;",103.53,95.10,95.10,94.63,95.58,356,ok,
-41,benchmarks/queries/query_41.sql,"SELECT WindowClientWidth, WindowClientHeight, COUNT(*) AS PageViews FROM hits WHERE CounterID = 62 AND EventDate >= '2013-07-01' AND EventDate <= '2013-07-31' AND IsRefresh = 0 AND DontCountHits = 0 AND URLHash = 2868770270353813622 GROUP BY WindowClientWidth, WindowClientHeight ORDER BY PageViews DESC LIMIT 10 OFFSET 10000;",39.71,34.90,34.88,34.50,35.36,132,ok,
-42,benchmarks/queries/query_42.sql,"SELECT DATE_TRUNC('minute', EventTime) AS M, COUNT(*) AS PageViews FROM hits WHERE CounterID = 62 AND EventDate >= '2013-07-14' AND EventDate <= '2013-07-15' AND IsRefresh = 0 AND DontCountHits = 0 GROUP BY DATE_TRUNC('minute', EventTime) ORDER BY DATE_TRUNC('minute', EventTime) LIMIT 10 OFFSET 1000;",68.37,69.46,69.69,68.04,70.42,240,ok,
+0,benchmarks/queries/query_0.sql,SELECT COUNT(*) FROM hits;,0.00,0.00,0.00,0.00,0.00,0,ok,
+1,benchmarks/queries/query_1.sql,SELECT COUNT(*) FROM hits WHERE AdvEngineID <> 0;,16.00,4.00,4.00,4.00,4.00,0,ok,
+2,benchmarks/queries/query_2.sql,"SELECT SUM(AdvEngineID), COUNT(*), AVG(ResolutionWidth) FROM hits;",31.00,7.00,7.00,7.00,7.00,0,ok,
+3,benchmarks/queries/query_3.sql,SELECT AVG(UserID) FROM hits;,24.00,6.00,6.00,6.00,6.00,0,ok,
+4,benchmarks/queries/query_4.sql,SELECT COUNT(DISTINCT UserID) FROM hits;,52.00,34.50,34.50,34.00,35.00,0,ok,
+5,benchmarks/queries/query_5.sql,SELECT COUNT(DISTINCT SearchPhrase) FROM hits;,65.00,36.75,36.50,36.00,38.00,0,ok,
+6,benchmarks/queries/query_6.sql,"SELECT MIN(EventDate), MAX(EventDate) FROM hits;",0.00,0.00,0.00,0.00,0.00,0,ok,
+7,benchmarks/queries/query_7.sql,"SELECT AdvEngineID, COUNT(*) FROM hits WHERE AdvEngineID <> 0 GROUP BY AdvEngineID ORDER BY COUNT(*) DESC;",18.00,7.75,8.00,7.00,8.00,0,ok,
+8,benchmarks/queries/query_8.sql,"SELECT RegionID, COUNT(DISTINCT UserID) AS u FROM hits GROUP BY RegionID ORDER BY u DESC LIMIT 10;",213.00,189.25,189.50,186.00,192.00,0,ok,
+9,benchmarks/queries/query_9.sql,"SELECT RegionID, SUM(AdvEngineID), COUNT(*) AS c, AVG(ResolutionWidth), COUNT(DISTINCT UserID) FROM hits GROUP BY RegionID ORDER BY c DESC LIMIT 10;",257.00,205.25,205.00,204.00,207.00,0,ok,
+10,benchmarks/queries/query_10.sql,"SELECT MobilePhoneModel, COUNT(DISTINCT UserID) AS u FROM hits WHERE MobilePhoneModel <> '' GROUP BY MobilePhoneModel ORDER BY u DESC LIMIT 10;",296.00,262.25,260.50,260.00,268.00,0,ok,
+11,benchmarks/queries/query_11.sql,"SELECT MobilePhone, MobilePhoneModel, COUNT(DISTINCT UserID) AS u FROM hits WHERE MobilePhoneModel <> '' GROUP BY MobilePhone, MobilePhoneModel ORDER BY u DESC LIMIT 10;",306.00,269.50,271.00,262.00,274.00,0,ok,
+12,benchmarks/queries/query_12.sql,"SELECT SearchPhrase, COUNT(*) AS c FROM hits WHERE SearchPhrase <> '' GROUP BY SearchPhrase ORDER BY c DESC LIMIT 10;",260.00,224.25,223.00,221.00,230.00,0,ok,
+13,benchmarks/queries/query_13.sql,"SELECT SearchPhrase, COUNT(DISTINCT UserID) AS u FROM hits WHERE SearchPhrase <> '' GROUP BY SearchPhrase ORDER BY u DESC LIMIT 10;",298.00,253.00,252.50,251.00,256.00,0,ok,
+14,benchmarks/queries/query_14.sql,"SELECT SearchEngineID, SearchPhrase, COUNT(*) AS c FROM hits WHERE SearchPhrase <> '' GROUP BY SearchEngineID, SearchPhrase ORDER BY c DESC LIMIT 10;",257.00,226.00,226.00,225.00,227.00,0,ok,
+15,benchmarks/queries/query_15.sql,"SELECT UserID, COUNT(*) FROM hits GROUP BY UserID ORDER BY COUNT(*) DESC LIMIT 10;",108.00,89.75,89.50,88.00,92.00,0,ok,
+16,benchmarks/queries/query_16.sql,"SELECT UserID, SearchPhrase, COUNT(*) FROM hits GROUP BY UserID, SearchPhrase ORDER BY COUNT(*) DESC LIMIT 10;",193.00,143.00,143.00,142.00,144.00,0,ok,
+17,benchmarks/queries/query_17.sql,"SELECT UserID, SearchPhrase, COUNT(*) FROM hits GROUP BY UserID, SearchPhrase LIMIT 10;",216.00,157.75,157.00,154.00,163.00,0,ok,
+18,benchmarks/queries/query_18.sql,"SELECT UserID, extract(minute FROM EventTime) AS m, SearchPhrase, COUNT(*) FROM hits GROUP BY UserID, m, SearchPhrase ORDER BY COUNT(*) DESC LIMIT 10;",589.00,517.50,516.00,509.00,529.00,0,ok,
+19,benchmarks/queries/query_19.sql,SELECT UserID FROM hits WHERE UserID = 435090932899640449;,3.00,0.00,0.00,0.00,0.00,0,ok,
+20,benchmarks/queries/query_20.sql,SELECT COUNT(*) FROM hits WHERE URL LIKE '%google%';,202.00,136.25,136.50,135.00,137.00,0,ok,
+21,benchmarks/queries/query_21.sql,"SELECT SearchPhrase, MIN(URL), COUNT(*) AS c FROM hits WHERE URL LIKE '%google%' AND SearchPhrase <> '' GROUP BY SearchPhrase ORDER BY c DESC LIMIT 10;",245.00,156.75,156.00,156.00,159.00,0,ok,
+22,benchmarks/queries/query_22.sql,"SELECT SearchPhrase, MIN(URL), MIN(Title), COUNT(*) AS c, COUNT(DISTINCT UserID) FROM hits WHERE Title LIKE '%Google%' AND URL NOT LIKE '%.google.%' AND SearchPhrase <> '' GROUP BY SearchPhrase ORDER BY c DESC LIMIT 10;",383.00,284.50,280.00,272.00,306.00,0,ok,
+23,benchmarks/queries/query_23.sql,SELECT * FROM hits WHERE URL LIKE '%google%' ORDER BY EventTime LIMIT 10;,365.00,241.25,239.00,238.00,249.00,0,ok,
+24,benchmarks/queries/query_24.sql,SELECT SearchPhrase FROM hits WHERE SearchPhrase <> '' ORDER BY EventTime LIMIT 10;,101.00,38.75,39.00,38.00,39.00,0,ok,
+25,benchmarks/queries/query_25.sql,SELECT SearchPhrase FROM hits WHERE SearchPhrase <> '' ORDER BY SearchPhrase LIMIT 10;,65.00,36.50,36.50,36.00,37.00,0,ok,
+26,benchmarks/queries/query_26.sql,"SELECT SearchPhrase FROM hits WHERE SearchPhrase <> '' ORDER BY EventTime, SearchPhrase LIMIT 10;",103.00,39.75,39.50,39.00,41.00,0,ok,
+27,benchmarks/queries/query_27.sql,"SELECT CounterID, AVG(STRLEN(URL)) AS l, COUNT(*) AS c FROM hits WHERE URL <> '' GROUP BY CounterID HAVING COUNT(*) > 100000 ORDER BY l DESC LIMIT 25;",534.00,454.75,450.50,447.00,471.00,0,ok,
+28,benchmarks/queries/query_28.sql,"SELECT REGEXP_REPLACE(Referer, '^https?://(?:www\.)?([^/]+)/.*$', '\1') AS k, AVG(STRLEN(Referer)) AS l, COUNT(*) AS c, MIN(Referer) FROM hits WHERE Referer <> '' GROUP BY k HAVING COUNT(*) > 100000 ORDER BY l DESC LIMIT 25;",993.00,940.75,940.00,934.00,949.00,0,ok,
+29,benchmarks/queries/query_29.sql,"SELECT SUM(ResolutionWidth), SUM(ResolutionWidth + 1), SUM(ResolutionWidth + 2), SUM(ResolutionWidth + 3), SUM(ResolutionWidth + 4), SUM(ResolutionWidth + 5), SUM(ResolutionWidth + 6), SUM(ResolutionWidth + 7), SUM(ResolutionWidth + 8), SUM(ResolutionWidth + 9), SUM(ResolutionWidth + 10), SUM(ResolutionWidth + 11), SUM(ResolutionWidth + 12), SUM(ResolutionWidth + 13), SUM(ResolutionWidth + 14), SUM(ResolutionWidth + 15), SUM(ResolutionWidth + 16), SUM(ResolutionWidth + 17), SUM(ResolutionWidth + 18), SUM(ResolutionWidth + 19), SUM(ResolutionWidth + 20), SUM(ResolutionWidth + 21), SUM(ResolutionWidth + 22), SUM(ResolutionWidth + 23), SUM(ResolutionWidth + 24), SUM(ResolutionWidth + 25), SUM(ResolutionWidth + 26), SUM(ResolutionWidth + 27), SUM(ResolutionWidth + 28), SUM(ResolutionWidth + 29), SUM(ResolutionWidth + 30), SUM(ResolutionWidth + 31), SUM(ResolutionWidth + 32), SUM(ResolutionWidth + 33), SUM(ResolutionWidth + 34), SUM(ResolutionWidth + 35), SUM(ResolutionWidth + 36), SUM(ResolutionWidth + 37), SUM(ResolutionWidth + 38), SUM(ResolutionWidth + 39), SUM(ResolutionWidth + 40), SUM(ResolutionWidth + 41), SUM(ResolutionWidth + 42), SUM(ResolutionWidth + 43), SUM(ResolutionWidth + 44), SUM(ResolutionWidth + 45), SUM(ResolutionWidth + 46), SUM(ResolutionWidth + 47), SUM(ResolutionWidth + 48), SUM(ResolutionWidth + 49), SUM(ResolutionWidth + 50), SUM(ResolutionWidth + 51), SUM(ResolutionWidth + 52), SUM(ResolutionWidth + 53), SUM(ResolutionWidth + 54), SUM(ResolutionWidth + 55), SUM(ResolutionWidth + 56), SUM(ResolutionWidth + 57), SUM(ResolutionWidth + 58), SUM(ResolutionWidth + 59), SUM(ResolutionWidth + 60), SUM(ResolutionWidth + 61), SUM(ResolutionWidth + 62), SUM(ResolutionWidth + 63), SUM(ResolutionWidth + 64), SUM(ResolutionWidth + 65), SUM(ResolutionWidth + 66), SUM(ResolutionWidth + 67), SUM(ResolutionWidth + 68), SUM(ResolutionWidth + 69), SUM(ResolutionWidth + 70), SUM(ResolutionWidth + 71), SUM(ResolutionWidth + 72), SUM(ResolutionWidth + 73), SUM(ResolutionWidth + 74), SUM(ResolutionWidth + 75), SUM(ResolutionWidth + 76), SUM(ResolutionWidth + 77), SUM(ResolutionWidth + 78), SUM(ResolutionWidth + 79), SUM(ResolutionWidth + 80), SUM(ResolutionWidth + 81), SUM(ResolutionWidth + 82), SUM(ResolutionWidth + 83), SUM(ResolutionWidth + 84), SUM(ResolutionWidth + 85), SUM(ResolutionWidth + 86), SUM(ResolutionWidth + 87), SUM(ResolutionWidth + 88), SUM(ResolutionWidth + 89) FROM hits;",17.00,4.75,5.00,4.00,5.00,0,ok,
+30,benchmarks/queries/query_30.sql,"SELECT SearchEngineID, ClientIP, COUNT(*) AS c, SUM(IsRefresh), AVG(ResolutionWidth) FROM hits WHERE SearchPhrase <> '' GROUP BY SearchEngineID, ClientIP ORDER BY c DESC LIMIT 10;",99.00,37.75,37.50,37.00,39.00,0,ok,
+31,benchmarks/queries/query_31.sql,"SELECT WatchID, ClientIP, COUNT(*) AS c, SUM(IsRefresh), AVG(ResolutionWidth) FROM hits WHERE SearchPhrase <> '' GROUP BY WatchID, ClientIP ORDER BY c DESC LIMIT 10;",161.00,53.50,52.50,51.00,58.00,0,ok,
+32,benchmarks/queries/query_32.sql,"SELECT WatchID, ClientIP, COUNT(*) AS c, SUM(IsRefresh), AVG(ResolutionWidth) FROM hits GROUP BY WatchID, ClientIP ORDER BY c DESC LIMIT 10;",744.00,633.25,623.00,614.00,673.00,0,ok,
+33,benchmarks/queries/query_33.sql,"SELECT URL, COUNT(*) AS c FROM hits GROUP BY URL ORDER BY c DESC LIMIT 10;",381.00,323.00,322.00,319.00,329.00,0,ok,
+34,benchmarks/queries/query_34.sql,"SELECT 1, URL, COUNT(*) AS c FROM hits GROUP BY 1, URL ORDER BY c DESC LIMIT 10;",386.00,323.75,323.00,319.00,330.00,0,ok,
+35,benchmarks/queries/query_35.sql,"SELECT ClientIP, ClientIP - 1, ClientIP - 2, ClientIP - 3, COUNT(*) AS c FROM hits GROUP BY ClientIP, ClientIP - 1, ClientIP - 2, ClientIP - 3 ORDER BY c DESC LIMIT 10;",43.00,20.00,20.00,20.00,20.00,0,ok,
+36,benchmarks/queries/query_36.sql,"SELECT URL, COUNT(*) AS PageViews FROM hits WHERE CounterID = 62 AND EventDate >= '2013-07-01' AND EventDate <= '2013-07-31' AND DontCountHits = 0 AND IsRefresh = 0 AND URL <> '' GROUP BY URL ORDER BY PageViews DESC LIMIT 10;",414.00,358.25,358.50,354.00,362.00,0,ok,
+37,benchmarks/queries/query_37.sql,"SELECT Title, COUNT(*) AS PageViews FROM hits WHERE CounterID = 62 AND EventDate >= '2013-07-01' AND EventDate <= '2013-07-31' AND DontCountHits = 0 AND IsRefresh = 0 AND Title <> '' GROUP BY Title ORDER BY PageViews DESC LIMIT 10;",284.00,242.25,242.50,240.00,244.00,0,ok,
+38,benchmarks/queries/query_38.sql,"SELECT URL, COUNT(*) AS PageViews FROM hits WHERE CounterID = 62 AND EventDate >= '2013-07-01' AND EventDate <= '2013-07-31' AND IsRefresh = 0 AND IsLink <> 0 AND IsDownload = 0 GROUP BY URL ORDER BY PageViews DESC LIMIT 10 OFFSET 1000;",118.00,70.25,70.50,68.00,72.00,0,ok,
+39,benchmarks/queries/query_39.sql,"SELECT TraficSourceID, SearchEngineID, AdvEngineID, CASE WHEN (SearchEngineID = 0 AND AdvEngineID = 0) THEN Referer ELSE '' END AS Src, URL AS Dst, COUNT(*) AS PageViews FROM hits WHERE CounterID = 62 AND EventDate >= '2013-07-01' AND EventDate <= '2013-07-31' AND IsRefresh = 0 GROUP BY TraficSourceID, SearchEngineID, AdvEngineID, Src, Dst ORDER BY PageViews DESC LIMIT 10 OFFSET 1000;",528.00,461.00,462.00,455.00,465.00,0,ok,
+40,benchmarks/queries/query_40.sql,"SELECT URLHash, EventDate, COUNT(*) AS PageViews FROM hits WHERE CounterID = 62 AND EventDate >= '2013-07-01' AND EventDate <= '2013-07-31' AND IsRefresh = 0 AND TraficSourceID IN (-1, 6) AND RefererHash = 3594120000172545465 GROUP BY URLHash, EventDate ORDER BY PageViews DESC LIMIT 10 OFFSET 100;",105.00,53.00,53.00,52.00,54.00,0,ok,
+41,benchmarks/queries/query_41.sql,"SELECT WindowClientWidth, WindowClientHeight, COUNT(*) AS PageViews FROM hits WHERE CounterID = 62 AND EventDate >= '2013-07-01' AND EventDate <= '2013-07-31' AND IsRefresh = 0 AND DontCountHits = 0 AND URLHash = 2868770270353813622 GROUP BY WindowClientWidth, WindowClientHeight ORDER BY PageViews DESC LIMIT 10 OFFSET 10000;",70.00,30.00,30.00,30.00,30.00,0,ok,
+42,benchmarks/queries/query_42.sql,"SELECT DATE_TRUNC('minute', EventTime) AS M, COUNT(*) AS PageViews FROM hits WHERE CounterID = 62 AND EventDate >= '2013-07-14' AND EventDate <= '2013-07-15' AND IsRefresh = 0 AND DontCountHits = 0 GROUP BY DATE_TRUNC('minute', EventTime) ORDER BY DATE_TRUNC('minute', EventTime) LIMIT 10 OFFSET 1000;",95.00,64.50,64.50,64.00,65.00,0,ok,
diff --git a/benchmarks/scheme.csv b/benchmarks/scheme.csv
index 881bb54..a3b7862 100644
--- a/benchmarks/scheme.csv
+++ b/benchmarks/scheme.csv
@@ -2,8 +2,8 @@ WatchID,int64
JavaEnable,int16
Title,string
GoodEvent,int16
-EventTime,TIMESTAMP
-EventDate,DATE
+EventTime,timestamp
+EventDate,date
CounterID,int32
ClientIP,int32
RegionID,int32
@@ -43,7 +43,7 @@ IsArtifical,int16
WindowClientWidth,int16
WindowClientHeight,int16
ClientTimeZone,int16
-ClientEventTime,TIMESTAMP
+ClientEventTime,timestamp
SilverlightVersion1,int16
SilverlightVersion2,int16
SilverlightVersion3,int32
@@ -62,7 +62,7 @@ IsParameter,int16
DontCountHits,int16
WithHash,int16
HitColor,string
-LocalEventTime,TIMESTAMP
+LocalEventTime,timestamp
Age,int16
Sex,int16
Income,int16
diff --git a/benchmarks/support/query_runners.cpp b/benchmarks/support/query_runners.cpp
new file mode 100644
index 0000000..61dbbb8
--- /dev/null
+++ b/benchmarks/support/query_runners.cpp
@@ -0,0 +1,435 @@
+#include "query_runners.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "common/error.h"
+
+static ExprPtr MakeExpr(const ExprKind kind, std::string output_name = {}) {
+ auto expr = std::make_shared();
+ expr->kind = kind;
+ expr->output_name = std::move(output_name);
+ return expr;
+}
+
+static ExprPtr Col(std::string name) {
+ auto expr = MakeExpr(ExprKind::Column, name);
+ expr->column = ColumnRef{.qualifier = {}, .name = std::move(name)};
+ return expr;
+}
+
+static ExprPtr Num(std::string text) {
+ auto expr = MakeExpr(ExprKind::Literal, text);
+ expr->literal = QueryLiteral{.text = std::move(text), .kind = LiteralKind::Numeric};
+ return expr;
+}
+
+static ExprPtr Str(std::string text) {
+ auto expr = MakeExpr(ExprKind::Literal, text);
+ expr->literal = QueryLiteral{.text = std::move(text), .kind = LiteralKind::String};
+ return expr;
+}
+
+static ExprPtr Ident(std::string text) {
+ auto expr = MakeExpr(ExprKind::Literal, text);
+ expr->literal = QueryLiteral{.text = std::move(text), .kind = LiteralKind::Identifier};
+ return expr;
+}
+
+static ExprPtr Star() { return MakeExpr(ExprKind::Star, "*"); }
+
+static std::string FormatFunctionName(const std::string_view function, const std::vector& args) {
+ std::string out(function);
+ out += "(";
+ for (size_t i = 0; i < args.size(); ++i) {
+ if (i > 0) {
+ out += ", ";
+ }
+ out += args[i]->output_name;
+ }
+ out += ")";
+ return out;
+}
+
+static ExprPtr Func(std::string name, std::vector args, std::string output_name = {}) {
+ auto expr = MakeExpr(ExprKind::Function);
+ expr->function_name = std::move(name);
+ expr->arguments = std::move(args);
+ expr->output_name =
+ output_name.empty() ? FormatFunctionName(expr->function_name, expr->arguments) : std::move(output_name);
+ return expr;
+}
+
+static ExprPtr ExtractMinute(ExprPtr expr) {
+ return Func("EXTRACT", {Ident("MINUTE"), std::move(expr)}, "EXTRACT(MINUTE, EventTime)");
+}
+
+static ExprPtr DateTruncMinute(ExprPtr expr) {
+ return Func("DATE_TRUNC", {Str("'minute'"), std::move(expr)}, "DATE_TRUNC('minute', EventTime)");
+}
+
+static ExprPtr Binary(ExprPtr left, const BinaryOp op, ExprPtr right) {
+ auto expr = MakeExpr(ExprKind::Binary);
+ expr->binary_op = op;
+ expr->output_name = left->output_name + (op == BinaryOp::Add ? " + " : " - ") + right->output_name;
+ expr->left = std::move(left);
+ expr->right = std::move(right);
+ return expr;
+}
+
+static ExprPtr Add(ExprPtr left, ExprPtr right) { return Binary(std::move(left), BinaryOp::Add, std::move(right)); }
+
+static ExprPtr Sub(ExprPtr left, ExprPtr right) {
+ return Binary(std::move(left), BinaryOp::Subtract, std::move(right));
+}
+
+static ExprPtr Case(PredicatePtr condition, ExprPtr then_expr, ExprPtr else_expr) {
+ auto expr = MakeExpr(ExprKind::Case, "CASE");
+ expr->case_spec = CaseSpec{
+ .condition = std::move(condition),
+ .then_expr = std::move(then_expr),
+ .else_expr = std::move(else_expr),
+ };
+ return expr;
+}
+
+static PredicatePtr Pred(const PredicateKind kind) {
+ auto pred = std::make_shared();
+ pred->kind = kind;
+ return pred;
+}
+
+static PredicatePtr Cmp(ExprPtr left, const ComparisonKind comparison, ExprPtr right) {
+ auto pred = Pred(PredicateKind::Comparison);
+ pred->left = std::move(left);
+ pred->comparison = comparison;
+ pred->right = std::move(right);
+ return pred;
+}
+
+static PredicatePtr Like(ExprPtr left, ExprPtr pattern, const bool negated = false) {
+ auto pred = Pred(negated ? PredicateKind::NotLike : PredicateKind::Like);
+ pred->left = std::move(left);
+ pred->right = std::move(pattern);
+ return pred;
+}
+
+static PredicatePtr In(ExprPtr left, std::vector values) {
+ auto pred = Pred(PredicateKind::In);
+ pred->left = std::move(left);
+ pred->values = std::move(values);
+ return pred;
+}
+
+static PredicatePtr And(PredicatePtr lhs, PredicatePtr rhs) {
+ auto pred = Pred(PredicateKind::And);
+ pred->lhs = std::move(lhs);
+ pred->rhs = std::move(rhs);
+ return pred;
+}
+
+static PredicatePtr All(const std::initializer_list predicates) {
+ auto it = predicates.begin();
+ PredicatePtr result = *it++;
+ for (; it != predicates.end(); ++it) {
+ result = And(std::move(result), *it);
+ }
+ return result;
+}
+
+static SelectItemSpec Select(ExprPtr expr, std::string alias = {}) {
+ SelectItemSpec item;
+ item.kind = SelectItemKind::GroupKey;
+ item.column = expr->kind == ExprKind::Column ? expr->column : ColumnRef{};
+ item.expression = std::move(expr);
+ item.output_name = alias.empty() ? item.expression->output_name : std::move(alias);
+ return item;
+}
+
+static SelectItemSpec Agg(std::string function, ExprPtr argument, const bool distinct = false, std::string alias = {}) {
+ AggSpec aggregate;
+ aggregate.function_name = std::move(function);
+ aggregate.distinct = distinct;
+ aggregate.argument_kind = argument->kind == ExprKind::Star ? AggArgumentKind::Star : AggArgumentKind::Column;
+
+ const std::string argument_name = argument->output_name;
+ if (aggregate.argument_kind == AggArgumentKind::Column) {
+ aggregate.argument = std::move(argument);
+ if (aggregate.argument->kind == ExprKind::Column) {
+ aggregate.column = aggregate.argument->column;
+ }
+ }
+
+ aggregate.output_name = aggregate.function_name + "(";
+ if (aggregate.argument_kind == AggArgumentKind::Star) {
+ aggregate.output_name += "*";
+ } else {
+ if (aggregate.distinct) {
+ aggregate.output_name += "DISTINCT ";
+ }
+ aggregate.output_name += argument_name;
+ }
+ aggregate.output_name += ")";
+
+ SelectItemSpec item;
+ item.kind = SelectItemKind::Aggregate;
+ item.aggregate = std::move(aggregate);
+ item.output_name = alias.empty() ? item.aggregate.output_name : std::move(alias);
+
+ return item;
+}
+
+static OrderBySpec Order(SelectItemSpec item, const bool descending = false) {
+ return OrderBySpec{.item = std::move(item), .descending = descending};
+}
+
+static OrderBySpec OrderExpr(ExprPtr expr, const bool descending = false) {
+ return Order(Select(std::move(expr)), descending);
+}
+
+static OrderBySpec OrderAgg(std::string function, ExprPtr argument, const bool descending = false) {
+ return Order(Agg(std::move(function), std::move(argument)), descending);
+}
+
+static Query Q(std::vector select_items, std::vector group_by = {}, PredicatePtr filter = {},
+ std::vector order_by = {}, const std::optional limit = {}, const size_t offset = 0,
+ PredicatePtr having = {}) {
+ Query query;
+ query.table_name = "hits";
+ query.select_items = std::move(select_items);
+ query.group_by = std::move(group_by);
+ query.filter = std::move(filter);
+ query.having = std::move(having);
+ query.order_by = std::move(order_by);
+ query.limit = limit;
+ query.offset = offset;
+ return query;
+}
+
+static std::optional BuildClickBenchQuery(const int id) {
+ switch (id) {
+ case 0:
+ return Q({Agg("COUNT", Star())});
+ case 1:
+ return Q({Agg("COUNT", Star())}, {}, Cmp(Col("AdvEngineID"), ComparisonKind::NotEqual, Num("0")));
+ case 2:
+ return Q({Agg("SUM", Col("AdvEngineID")), Agg("COUNT", Star()), Agg("AVG", Col("ResolutionWidth"))});
+ case 3:
+ return Q({Agg("AVG", Col("UserID"))});
+ case 4:
+ return Q({Agg("COUNT", Col("UserID"), true)});
+ case 5:
+ return Q({Agg("COUNT", Col("SearchPhrase"), true)});
+ case 6:
+ return Q({Agg("MIN", Col("EventDate")), Agg("MAX", Col("EventDate"))});
+ case 7:
+ return Q({Select(Col("AdvEngineID")), Agg("COUNT", Star())}, {Col("AdvEngineID")},
+ Cmp(Col("AdvEngineID"), ComparisonKind::NotEqual, Num("0")), {OrderAgg("COUNT", Star(), true)});
+ case 8:
+ return Q({Select(Col("RegionID")), Agg("COUNT", Col("UserID"), true, "u")}, {Col("RegionID")}, {},
+ {OrderExpr(Col("u"), true)}, 10);
+ case 9:
+ return Q({Select(Col("RegionID")), Agg("SUM", Col("AdvEngineID")), Agg("COUNT", Star(), false, "c"),
+ Agg("AVG", Col("ResolutionWidth")), Agg("COUNT", Col("UserID"), true)},
+ {Col("RegionID")}, {}, {OrderExpr(Col("c"), true)}, 10);
+ case 10:
+ return Q({Select(Col("MobilePhoneModel")), Agg("COUNT", Col("UserID"), true, "u")},
+ {Col("MobilePhoneModel")}, Cmp(Col("MobilePhoneModel"), ComparisonKind::NotEqual, Str("''")),
+ {OrderExpr(Col("u"), true)}, 10);
+ case 11:
+ return Q(
+ {Select(Col("MobilePhone")), Select(Col("MobilePhoneModel")), Agg("COUNT", Col("UserID"), true, "u")},
+ {Col("MobilePhone"), Col("MobilePhoneModel")},
+ Cmp(Col("MobilePhoneModel"), ComparisonKind::NotEqual, Str("''")), {OrderExpr(Col("u"), true)}, 10);
+ case 12:
+ return Q({Select(Col("SearchPhrase")), Agg("COUNT", Star(), false, "c")}, {Col("SearchPhrase")},
+ Cmp(Col("SearchPhrase"), ComparisonKind::NotEqual, Str("''")), {OrderExpr(Col("c"), true)}, 10);
+ case 13:
+ return Q({Select(Col("SearchPhrase")), Agg("COUNT", Col("UserID"), true, "u")}, {Col("SearchPhrase")},
+ Cmp(Col("SearchPhrase"), ComparisonKind::NotEqual, Str("''")), {OrderExpr(Col("u"), true)}, 10);
+ case 14:
+ return Q({Select(Col("SearchEngineID")), Select(Col("SearchPhrase")), Agg("COUNT", Star(), false, "c")},
+ {Col("SearchEngineID"), Col("SearchPhrase")},
+ Cmp(Col("SearchPhrase"), ComparisonKind::NotEqual, Str("''")), {OrderExpr(Col("c"), true)}, 10);
+ case 15:
+ return Q({Select(Col("UserID")), Agg("COUNT", Star())}, {Col("UserID")}, {},
+ {OrderAgg("COUNT", Star(), true)}, 10);
+ case 16:
+ return Q({Select(Col("UserID")), Select(Col("SearchPhrase")), Agg("COUNT", Star())},
+ {Col("UserID"), Col("SearchPhrase")}, {}, {OrderAgg("COUNT", Star(), true)}, 10);
+ case 17:
+ return Q({Select(Col("UserID")), Select(Col("SearchPhrase")), Agg("COUNT", Star())},
+ {Col("UserID"), Col("SearchPhrase")}, {}, {}, 10);
+ case 18:
+ return Q({Select(Col("UserID")), Select(ExtractMinute(Col("EventTime")), "m"), Select(Col("SearchPhrase")),
+ Agg("COUNT", Star())},
+ {Col("UserID"), Col("m"), Col("SearchPhrase")}, {}, {OrderAgg("COUNT", Star(), true)}, 10);
+ case 19:
+ return Q({Select(Col("UserID"))}, {}, Cmp(Col("UserID"), ComparisonKind::Equal, Num("435090932899640449")));
+ case 20:
+ return Q({Agg("COUNT", Star())}, {}, Like(Col("URL"), Str("'%google%'")));
+ case 21:
+ return Q({Select(Col("SearchPhrase")), Agg("MIN", Col("URL")), Agg("COUNT", Star(), false, "c")},
+ {Col("SearchPhrase")},
+ All({Like(Col("URL"), Str("'%google%'")),
+ Cmp(Col("SearchPhrase"), ComparisonKind::NotEqual, Str("''"))}),
+ {OrderExpr(Col("c"), true)}, 10);
+ case 22:
+ return Q({Select(Col("SearchPhrase")), Agg("MIN", Col("URL")), Agg("MIN", Col("Title")),
+ Agg("COUNT", Star(), false, "c"), Agg("COUNT", Col("UserID"), true)},
+ {Col("SearchPhrase")},
+ All({Like(Col("Title"), Str("'%Google%'")), Like(Col("URL"), Str("'%.google.%'"), true),
+ Cmp(Col("SearchPhrase"), ComparisonKind::NotEqual, Str("''"))}),
+ {OrderExpr(Col("c"), true)}, 10);
+ case 23:
+ return Q({Select(Star())}, {}, Like(Col("URL"), Str("'%google%'")), {OrderExpr(Col("EventTime"))}, 10);
+ case 24:
+ return Q({Select(Col("SearchPhrase"))}, {}, Cmp(Col("SearchPhrase"), ComparisonKind::NotEqual, Str("''")),
+ {OrderExpr(Col("EventTime"))}, 10);
+ case 25:
+ return Q({Select(Col("SearchPhrase"))}, {}, Cmp(Col("SearchPhrase"), ComparisonKind::NotEqual, Str("''")),
+ {OrderExpr(Col("SearchPhrase"))}, 10);
+ case 26:
+ return Q({Select(Col("SearchPhrase"))}, {}, Cmp(Col("SearchPhrase"), ComparisonKind::NotEqual, Str("''")),
+ {OrderExpr(Col("EventTime")), OrderExpr(Col("SearchPhrase"))}, 10);
+ case 27:
+ return Q({Select(Col("CounterID")), Agg("AVG", Func("STRLEN", {Col("URL")}), false, "l"),
+ Agg("COUNT", Star(), false, "c")},
+ {Col("CounterID")}, Cmp(Col("URL"), ComparisonKind::NotEqual, Str("''")),
+ {OrderExpr(Col("l"), true)}, 25, 0, Cmp(Col("c"), ComparisonKind::Greater, Num("100000")));
+ case 28:
+ return Q({Select(Func("REGEXP_REPLACE",
+ {Col("Referer"), Str(R"('^https?://(?:www\.)?([^/]+)/.*$')"), Str(R"('\1')")},
+ "REGEXP_REPLACE(Referer, '^https?://(?:www\\.)?([^/]+)/.*$', '\\1')"),
+ "k"),
+ Agg("AVG", Func("STRLEN", {Col("Referer")}), false, "l"), Agg("COUNT", Star(), false, "c"),
+ Agg("MIN", Col("Referer"))},
+ {Col("k")}, Cmp(Col("Referer"), ComparisonKind::NotEqual, Str("''")), {OrderExpr(Col("l"), true)},
+ 25, 0, Cmp(Col("c"), ComparisonKind::Greater, Num("100000")));
+ case 29: {
+ std::vector items;
+ items.push_back(Agg("SUM", Col("ResolutionWidth")));
+ for (int offset = 1; offset <= 89; ++offset) {
+ items.push_back(Agg("SUM", Add(Col("ResolutionWidth"), Num(std::to_string(offset)))));
+ }
+ return Q(std::move(items));
+ }
+ case 30:
+ return Q({Select(Col("SearchEngineID")), Select(Col("ClientIP")), Agg("COUNT", Star(), false, "c"),
+ Agg("SUM", Col("IsRefresh")), Agg("AVG", Col("ResolutionWidth"))},
+ {Col("SearchEngineID"), Col("ClientIP")},
+ Cmp(Col("SearchPhrase"), ComparisonKind::NotEqual, Str("''")), {OrderExpr(Col("c"), true)}, 10);
+ case 31:
+ return Q({Select(Col("WatchID")), Select(Col("ClientIP")), Agg("COUNT", Star(), false, "c"),
+ Agg("SUM", Col("IsRefresh")), Agg("AVG", Col("ResolutionWidth"))},
+ {Col("WatchID"), Col("ClientIP")}, Cmp(Col("SearchPhrase"), ComparisonKind::NotEqual, Str("''")),
+ {OrderExpr(Col("c"), true)}, 10);
+ case 32:
+ return Q({Select(Col("WatchID")), Select(Col("ClientIP")), Agg("COUNT", Star(), false, "c"),
+ Agg("SUM", Col("IsRefresh")), Agg("AVG", Col("ResolutionWidth"))},
+ {Col("WatchID"), Col("ClientIP")}, {}, {OrderExpr(Col("c"), true)}, 10);
+ case 33:
+ return Q({Select(Col("URL")), Agg("COUNT", Star(), false, "c")}, {Col("URL")}, {},
+ {OrderExpr(Col("c"), true)}, 10);
+ case 34:
+ return Q({Select(Num("1")), Select(Col("URL")), Agg("COUNT", Star(), false, "c")}, {Num("1"), Col("URL")},
+ {}, {OrderExpr(Col("c"), true)}, 10);
+ case 35:
+ return Q({Select(Col("ClientIP")), Select(Sub(Col("ClientIP"), Num("1"))),
+ Select(Sub(Col("ClientIP"), Num("2"))), Select(Sub(Col("ClientIP"), Num("3"))),
+ Agg("COUNT", Star(), false, "c")},
+ {Col("ClientIP"), Sub(Col("ClientIP"), Num("1")), Sub(Col("ClientIP"), Num("2")),
+ Sub(Col("ClientIP"), Num("3"))},
+ {}, {OrderExpr(Col("c"), true)}, 10);
+ case 36:
+ return Q({Select(Col("URL")), Agg("COUNT", Star(), false, "PageViews")}, {Col("URL")},
+ All({Cmp(Col("CounterID"), ComparisonKind::Equal, Num("62")),
+ Cmp(Col("EventDate"), ComparisonKind::GreaterOrEqual, Str("'2013-07-01'")),
+ Cmp(Col("EventDate"), ComparisonKind::LessOrEqual, Str("'2013-07-31'")),
+ Cmp(Col("DontCountHits"), ComparisonKind::Equal, Num("0")),
+ Cmp(Col("IsRefresh"), ComparisonKind::Equal, Num("0")),
+ Cmp(Col("URL"), ComparisonKind::NotEqual, Str("''"))}),
+ {OrderExpr(Col("PageViews"), true)}, 10);
+ case 37:
+ return Q({Select(Col("Title")), Agg("COUNT", Star(), false, "PageViews")}, {Col("Title")},
+ All({Cmp(Col("CounterID"), ComparisonKind::Equal, Num("62")),
+ Cmp(Col("EventDate"), ComparisonKind::GreaterOrEqual, Str("'2013-07-01'")),
+ Cmp(Col("EventDate"), ComparisonKind::LessOrEqual, Str("'2013-07-31'")),
+ Cmp(Col("DontCountHits"), ComparisonKind::Equal, Num("0")),
+ Cmp(Col("IsRefresh"), ComparisonKind::Equal, Num("0")),
+ Cmp(Col("Title"), ComparisonKind::NotEqual, Str("''"))}),
+ {OrderExpr(Col("PageViews"), true)}, 10);
+ case 38:
+ return Q({Select(Col("URL")), Agg("COUNT", Star(), false, "PageViews")}, {Col("URL")},
+ All({Cmp(Col("CounterID"), ComparisonKind::Equal, Num("62")),
+ Cmp(Col("EventDate"), ComparisonKind::GreaterOrEqual, Str("'2013-07-01'")),
+ Cmp(Col("EventDate"), ComparisonKind::LessOrEqual, Str("'2013-07-31'")),
+ Cmp(Col("IsRefresh"), ComparisonKind::Equal, Num("0")),
+ Cmp(Col("IsLink"), ComparisonKind::NotEqual, Num("0")),
+ Cmp(Col("IsDownload"), ComparisonKind::Equal, Num("0"))}),
+ {OrderExpr(Col("PageViews"), true)}, 10, 1000);
+ case 39:
+ return Q({Select(Col("TraficSourceID")), Select(Col("SearchEngineID")), Select(Col("AdvEngineID")),
+ Select(Case(All({Cmp(Col("SearchEngineID"), ComparisonKind::Equal, Num("0")),
+ Cmp(Col("AdvEngineID"), ComparisonKind::Equal, Num("0"))}),
+ Col("Referer"), Str("''")),
+ "Src"),
+ Select(Col("URL"), "Dst"), Agg("COUNT", Star(), false, "PageViews")},
+ {Col("TraficSourceID"), Col("SearchEngineID"), Col("AdvEngineID"), Col("Src"), Col("Dst")},
+ All({Cmp(Col("CounterID"), ComparisonKind::Equal, Num("62")),
+ Cmp(Col("EventDate"), ComparisonKind::GreaterOrEqual, Str("'2013-07-01'")),
+ Cmp(Col("EventDate"), ComparisonKind::LessOrEqual, Str("'2013-07-31'")),
+ Cmp(Col("IsRefresh"), ComparisonKind::Equal, Num("0"))}),
+ {OrderExpr(Col("PageViews"), true)}, 10, 1000);
+ case 40:
+ return Q({Select(Col("URLHash")), Select(Col("EventDate")), Agg("COUNT", Star(), false, "PageViews")},
+ {Col("URLHash"), Col("EventDate")},
+ All({Cmp(Col("CounterID"), ComparisonKind::Equal, Num("62")),
+ Cmp(Col("EventDate"), ComparisonKind::GreaterOrEqual, Str("'2013-07-01'")),
+ Cmp(Col("EventDate"), ComparisonKind::LessOrEqual, Str("'2013-07-31'")),
+ Cmp(Col("IsRefresh"), ComparisonKind::Equal, Num("0")),
+ In(Col("TraficSourceID"), {Num("-1"), Num("6")}),
+ Cmp(Col("RefererHash"), ComparisonKind::Equal, Num("3594120000172545465"))}),
+ {OrderExpr(Col("PageViews"), true)}, 10, 100);
+ case 41:
+ return Q({Select(Col("WindowClientWidth")), Select(Col("WindowClientHeight")),
+ Agg("COUNT", Star(), false, "PageViews")},
+ {Col("WindowClientWidth"), Col("WindowClientHeight")},
+ All({Cmp(Col("CounterID"), ComparisonKind::Equal, Num("62")),
+ Cmp(Col("EventDate"), ComparisonKind::GreaterOrEqual, Str("'2013-07-01'")),
+ Cmp(Col("EventDate"), ComparisonKind::LessOrEqual, Str("'2013-07-31'")),
+ Cmp(Col("IsRefresh"), ComparisonKind::Equal, Num("0")),
+ Cmp(Col("DontCountHits"), ComparisonKind::Equal, Num("0")),
+ Cmp(Col("URLHash"), ComparisonKind::Equal, Num("2868770270353813622"))}),
+ {OrderExpr(Col("PageViews"), true)}, 10, 10000);
+ case 42:
+ return Q({Select(DateTruncMinute(Col("EventTime")), "M"), Agg("COUNT", Star(), false, "PageViews")},
+ {Col("M")},
+ All({Cmp(Col("CounterID"), ComparisonKind::Equal, Num("62")),
+ Cmp(Col("EventDate"), ComparisonKind::GreaterOrEqual, Str("'2013-07-14'")),
+ Cmp(Col("EventDate"), ComparisonKind::LessOrEqual, Str("'2013-07-15'")),
+ Cmp(Col("IsRefresh"), ComparisonKind::Equal, Num("0")),
+ Cmp(Col("DontCountHits"), ComparisonKind::Equal, Num("0"))}),
+ {OrderExpr(Col("M"))}, 10, 1000);
+ default:
+ return std::nullopt;
+ }
+}
+
+bool HasHardcodedClickBenchQuery(const int query_id) { return query_id >= 0 && query_id <= 42; }
+
+Query BuildRequiredClickBenchQuery(const int query_id) {
+ auto query = BuildClickBenchQuery(query_id);
+ if (!query.has_value()) {
+ throw Error::InvalidArgument("benchmark", "unknown ClickBench query id");
+ }
+ return std::move(*query);
+}
+
+ExecuteExpected RunHardcodedClickBenchQuery(const Executor& executor, const int query_id) {
+ return executor.Execute(BuildRequiredClickBenchQuery(query_id));
+}
diff --git a/benchmarks/support/query_runners.h b/benchmarks/support/query_runners.h
index 0bfdd40..bf78315 100644
--- a/benchmarks/support/query_runners.h
+++ b/benchmarks/support/query_runners.h
@@ -1,272 +1,20 @@
#pragma once
-#include
-#include