ClickHouse: Release 26.7 Call

Author: Alexey Milovidov, 2026-07-23.

ClickHouse Release 26.7

ClickHouse release 26.7

1. (50 min) What's new in ClickHouse 26.7.

2. (10 min) Q&A.

Release 26.7

— 64 new features 🌻

— 117 performance optimizations ⛱️

— 349 bug fixes 🍉

Small And Nice Features

groupFormat

An aggregate function that formats each group's rows
with any output format and returns the result as a string:

SELECT user, groupFormat('Markdown')(action, ts) AS history FROM events GROUP BY user; -- a rendered Markdown table per user SELECT id, groupFormat('JSONEachRow')(*) FROM t GROUP BY id;

— Works with all output formats: CSV, JSON, Vertical, XML, …
— Perfect for feeding grouped data to LLMs, webhooks, and reports.

Developer: Yang Hu.

-Tuple combinator

Apply an aggregate function to every element of a Tuple at once:

SELECT sumTuple((clicks, views, purchases)) FROM events; -- (1234, 56789, 42) — one sum per element SELECT corrTuple((a1, a2), (b1, b2)); -- (corr(a1, b1), corr(a2, b2)) — arguments paired by position -- Note: this was already possible SELECT COLUMNS('^metric_') APPLY sum FROM table;

— Unlike -ForEach (for Arrays), elements may have different types.
— Element names and types are preserved in the result.

Developer: RinChanNOW.

WHERE in projections

A projection can now materialize only the rows matching a predicate:

ALTER TABLE hits ADD PROJECTION errors ( SELECT ts, status, url WHERE status >= 400 ORDER BY status ); -- reads the tiny projection: 4 granules instead of 10M rows SELECT count() FROM hits WHERE status >= 400;

— The optimizer uses it (cost-based) when the query's WHERE
  implies the projection's WHERE.
— A subset of data, that works faster, without the need of a separate table.

Developer: S Bala Vignesh.

Unification of URL

The url table function and URL engine now dispatch
to the right backend based on the URL scheme:

SELECT * FROM url('file://data/hits.csv'); -- File SELECT * FROM url('s3://bucket/data/*.parquet'); -- S3 SELECT * FROM url('gs://bucket/table.parquet'); -- S3 (GCS) SELECT * FROM url('az://container/blob.csv'); -- Azure SELECT * FROM url('hdfs://nn:8020/path'); -- HDFS

— One function to read them all.
http(s):// works as before.
s3, gs, etc. use the environment credentials.

Developer: Alexey Milovidov.

eval 🧪

A table function that builds a query string from an expression and runs it:

SET allow_experimental_eval_table_function = 1; SELECT * FROM eval( 'SELECT number FROM numbers(' || toString(2 + 1) || ')'); -- 0, 1, 2 -- the argument can also be a subquery, not wrapped in a string — -- e.g., generate a query that sums every numeric column of a table: SELECT * FROM eval(( SELECT 'SELECT ' || arrayStringConcat(groupArray('sum(' || name || ')'), ', ') || ' FROM metrics' FROM system.columns WHERE table = 'metrics' AND type LIKE '%Int%'));

— Dynamic SQL without external scripting.

Developers: Yue Ni, Alexey Milovidov.

Data Federation

Remote and RemoteSecure engines

The remote table function now has persistent counterparts:

CREATE TABLE events_on_prod ENGINE = Remote('prod:9000', default, events); -- no column list needed: the structure is inferred from the remote table SELECT count() FROM events_on_prod; -- reads remotely INSERT INTO events_on_prod VALUES …; -- writes remotely -- Note: this was already possible: CREATE TABLE events_on_prod AS remote('prod:9000', default, events);

— A permanent "symlink" to a table on another server.
RemoteSecure — the same over TLS.
— Supports cluster addresses: Remote('host{1..3}:9000', …).

Developer: Alexey Milovidov.

Forward queries to external databases

mysql, postgresql, and sqlite accept a query instead of a table name
and pass it to the external database as is:

SELECT * FROM postgresql('host:5432', 'db', query($$ SELECT date_trunc('week', day) AS w, count() FROM pageviews GROUP BY w $$), 'user', 'pass'); -- runs inside PostgreSQL, with PostgreSQL functions SELECT * FROM sqlite('db.sqlite', (SELECT customer, sum(amount) FROM orders GROUP BY customer)); -- subquery form

— The result structure is inferred from the query. Read-only.
— Aggregate remotely, transfer only the result.

Developers: Denis Vidiaev, Alexey Milovidov.

Wildcards over HTTP index pages 🧪

The url table function expands wildcards by crawling index pages:

SET allow_experimental_url_wildcard_from_index_pages = 1; SELECT * FROM url( 'https://dumps.wikimedia.org/other/pageviews/2026/2026-01/pageviews*.gz'); -- lists the HTML/plaintext directory pages, follows matching links

— Works with autogenerated directory listings (nginx, S3 websites, …).
— With limits on the index page size and the number of directories read.

Developer: Yue Ni.

Vector Search

QBit Improvements

A data type for vector embeddings,
that allows tuning the search precision at runtime.
Production-ready since 26.2:

CREATE TABLE vectors ( id UInt64, name String, ... vec QBit(BFloat16, 1536) ) ORDER BY ();

SELECT id, name FROM vectors ORDER BY L2DistanceTransposed(vec, target, 10) LIMIT 10;

QBit

It uses a bit-sliced data layout:
every number is sliced by bits,
e.g., for 1536-dim vector of BFloat16,
we store 16 subcolumns with Nth (1..16th) bits from all dimensions.

At the query time, we specify, how many (most significant) bits to take.

For example, we can ask to read
only 10 out of 16 bits.

QBit: Int8 quantization

QBit now supports Int8, which allows anything from binary (1 bit) to full 8 bit quantization, chosen at runtime per query.

It can store any Int8 codes, and we also provide quantizeBFloat16ToInt8 and dequantizeInt8ToBFloat16 functions for optimal conversion from Float to Int8, minimizing the error on gaussian-distributed vector coordinates.

CREATE TABLE images (id UInt64, emb QBit(Int8, 2048)) …; INSERT INTO images SELECT id, quantizeBFloat16ToInt8(embedding * sqrt(2048)) FROM src; -- scale unit-normalized embeddings by sqrt(dim) and convert to Int8 SELECT id FROM images ORDER BY cosineDistanceTransposedQuantized(emb, target, 4) LIMIT 10; -- reads only the top 4 bit-planes — half the I/O of 8-bit

Developer: Alexey Milovidov.

QBit: strided storage

The optional stride parameter slices dimensions into groups — each bit-plane of each group is its own stream on disk: QBit(Int8, 1024, 256):

dims 1–256 257–512 513–768 769–1024
bit 1 (sign)
bit 2
bit 3
bit 4
bit 5 … 8

… ORDER BY cosineDistanceTransposedQuantized(emb, target, 4, 256) … -- 4 bits × first 256 dims: reads the 4 green streams of 32 — 3% of a Float32 column

You can request reading only first N dimensions - good for MRL (Matryoshka Representation Learning) embeddings to tune between the speed and recall.

Developer: Alexey Milovidov.

Randomized Hadamard rotations

To improve the quality of vector search, it makes sense to apply random rotation of N-dimensional space before quantization of vectors.

Rotation is a multiplication to an orthogonal matrix. There are many orthogonal matrices, and matrix multiplication is computationally expensive.

Thankfully, there is a family of orthogonal matrices, that are faster to multiply with - Hadamard matrices. And it is broad enough to represent pseudorandom rotations.

Now ClickHouse has a function for pseudorandom rotations:

SELECT randomHadamardTransform(vec);

Developer: Alexey Milovidov.

Randomized Hadamard rotations

A building block for vector quantization pipelines:

SELECT randomHadamardTransform([1., 2., 3., 4.]::Array(Float32)); -- [0, 2, 1, -5] — an orthogonal, norm-preserving rotation SELECT randomHadamardTransform(v, seed); -- different rotation SELECT randomHadamardTransform(v, seed, 256); -- truncate to 256 dims

— Spreads the information evenly across dimensions,
  so scalar quantization loses less — rotate, then quantize.
— Truncated form = Johnson–Lindenstrauss random projection.
— Deterministic: the same seed gives the same rotation.

Developer: Alexey Milovidov.

Quantization codecs 🧪

Store a compact quantized companion next to full-precision vectors:

CREATE TABLE vecs (id UInt32, v Array(BFloat16) CODEC(Quantized('rabitq', 384))) …; -- methods: int8, rabitq (1-bit), turboquant (2-bit), mrl, pq SET vector_search_use_quantized_codes = 1; SELECT id FROM vecs ORDER BY L2Distance(v, […]) LIMIT 10;

— Two-stage brute-force search without an index: scan the small
  quantized stream, then rescore the candidates at full precision.
— Up to 8x less I/O in the first stage (1-bit codes: 16x smaller).

Developer: Shankar Iyer.

Text Search

Positions for phrase matching

Text indexes can now store token positions — for exact phrase search:

CREATE TABLE docs (…, INDEX idx body TYPE text( tokenizer = 'splitByNonAlpha', support_phrase_search = 1)) … SETTINGS allow_experimental_text_index_phrase_search = 1; SELECT count() FROM docs WHERE hasPhrase(body, 'quick brown fox'); -- 1 — but hasPhrase(body, 'brown quick fox') = 0: order matters

— The phrase test is answered directly from the index:
  in our test, 124 granules → 1, and no column data was read at all.

Developer: Elmi Ahmadov.

Geospatial

Universal Transverse Mercator

Convert between WGS84 coordinates and the UTM / MGRS systems
used in surveying, mapping, and military grids:

UTM zones: 60 longitude zones and latitude bands C–X on a world map

Map: NASA Visible Earth / Wikimedia Commons, public domain.

SELECT geoToUTM(4.89, 52.36) AS amsterdam; -- (628700.24, 5802760.82, 31, 'U') -- easting, northing, zone, band SELECT UTMToGeo(628700.24, 5802760.82, 31, true); -- (4.89, 52.36) — and back SELECT geoToMGRS(4.89, 52.36); -- '31UFU2870002760' SELECT MGRSToGeo('31UFU2870002760'); -- (4.89, 52.36)

Developer: Alexey Milovidov.

GeoJSON output

26.6 added GeoJSON input. 26.7 writes it, too:

SELECT id, (13.4050, 52.5200)::Point AS geometry, 'Berlin' AS name FORMAT GeoJSON

{"type":"FeatureCollection","features":[ {"type":"Feature","id":1, "geometry":{"type":"Point","coordinates":[13.405,52.52]}, "properties":{"name":"Berlin"}}, …]}

— The geo column → geometry, the id column → feature id,
  everything else → properties.
— Feed query results straight to Leaflet, Mapbox, deck.gl, QGIS.

Developers: Mark Needham, Nihal Z. Miaji.

Geometry intersection functions

Do two shapes intersect — whatever their types are?

SELECT geometryIntersectCartesian( [[(0., 0.), (10., 0.), (10., 10.), (0., 10.)]]::Polygon, [(5., 5.), (15., 15.)]::LineString); -- 1 SELECT geometryIntersectSpherical(route, restricted_zone);

— Unlike polygonsIntersect*, they accept any geometry type:
  Point, LineString, MultiLineString, Ring, Polygon, MultiPolygon —
  including the umbrella Geometry type, and the arguments may differ.

Developer: Alexey Milovidov.

Data Lakes

Iceberg manifest compaction

Frequent inserts produce many small manifest files.
Now ClickHouse can compact the metadata — without rewriting data:

SET allow_experimental_iceberg_compaction = 1; OPTIMIZE TABLE ice MANIFEST; -- 13 manifests merged into 1; a new 'replace' snapshot is committed

— Faster planning for every subsequent query on the table.
— Triggered when the manifest list exceeds
iceberg_manifest_min_count_to_compact (default 30).
— Data files are untouched; time travel keeps working.

Developer: Smita Kulkarni.

Data lakes, elsewhere

Delta Lake writes are now Beta (were experimental):

SET allow_experimental_delta_lake_writes = 1; INSERT INTO delta_table VALUES (3, 'written'), (4, 'by clickhouse'); -- commits a new Delta log version; readable by Spark, Trino, Python

Microsoft OneLake: authentication with a bearer token:

CREATE DATABASE onelake ENGINE = DataLakeCatalog('https://onelake.…') SETTINGS catalog_type = 'onelake', onelake_bearer_token = '…';

— No need to share a long-lived client secret.

Developers: Kseniia Sumarokova, Asya Shneerson.

Web UI

Tabs in the Web UI

The built-in /play UI now has tabs for working with multiple queries:

— Tabs, titles, parameters, and small result snapshots
  are persisted across reloads.
— Integrated with browser history and the URL.
— Middle-click a tab to duplicate it; switch tabs with the mouse wheel.
— Middle-click a table in the database panel to open it in a new tab.
— Connection credentials are tucked behind a key button.

Demo

Developer: Alexey Milovidov.

Color coding, pins, autocompletion

The result table became much more powerful:

Color coding per column (the 🌈 toggle in the header):
  bar / heatmap / categorical — remembered in the URL.
Pinned columns (📌): keep key columns visible while scrolling.
Autocompletion from system.completions + a WASM SQL lexer.
Full keyboard navigation: arrows in the database panel and
  the result table, focus outlines, accessible toolbar.
— Rainbow parentheses, digit-group highlighting, Tab indentation,
  syntax errors highlighted in place.

Developer: Alexey Milovidov.

Database panel improvements

The left panel of the Web UI grew up:

— Table count next to each expanded database.
— A refresh button to reload the table list.
— Expanded databases are restored when the panel reopens.
— Click a table's icon to see its columns — with type icons,
  a size bar per column, and compression ratios in tooltips.
— Selecting a database makes it the default for queries.

Demo

Developer: Alexey Milovidov.

Instant reference docs

A new documentation page, embedded in the server:

http://localhost:8123/docs

— Instant search over system.documentation
  functions, settings, table engines, data types, formats, …
— Rendered reference docs with syntax highlighting, math,
  and cross-links. Works offline, always matches your server version.

Demo

Developer: Alexey Milovidov.

JOIN Performance

The right table is an index

A JOIN can use the values of the right-hand side to prune granules
of the left table via its primary key or skip indexes:

SET enable_join_runtime_filters_index_analysis = 1; SELECT … FROM facts JOIN lookup ON facts.id = lookup.id; -- the ids from `lookup` become an index condition on `facts`

Measured — 100M-row table joined with a 100-row table:
  granules read: 12216 → 100 (122x),
  time: 0.177 s → 0.022 s (8x).

Developer: Shankar Iyer.

Packed row references

The right-hand side of a hash join now uses a compact
8-byte index-based row reference — for every key type:

— Hash-table entries of ALL joins are now as small as those of ANY joins.
— Benchmarked on 100–300M row joins: median 12% faster,
15% less peak memory; INNER on UInt64 keys: 21% faster, 38% less memory.

A test: 100M × 150M parallel_hash INNER JOIN:

26.6: 14.4 GB, 0.84 sec.
26.7: 8.0 GB, 0.66 sec.

Developer: Harikrishnan Prabakaran.

DPsub JOIN reordering

A new JOIN-order optimization algorithm —
dynamic programming over subsets:

SET query_plan_optimize_join_order_algorithm = 'dpsub';

— Considers all JOIN orders — finds the optimal plan.
— Lower optimization overhead than dpsize.
— Supports non-inner joins, unlike dpsize and dphyp.
— Algorithms can be chained: 'dpsub,greedy' — tried in order,
  with fallback for queries an algorithm cannot handle.

Developer: Fisnik Kastrati.

More Performance

A JIT-compiled regexp engine

Simple regular expressions are now compiled to native code with LLVM:

SELECT count() FROM logs WHERE match(line, '^[a-z]+[0-9]+@example[0-9]+\\.com$');

— Applies to match, extract, extractAll, replaceRegexpOne/All, LIKE.
compile_regular_expressions — on by default; unsupported patterns
  transparently fall back to RE2.

A test: match() over 20M strings:

26.6: 2.7 sec.
26.7: 1.1 sec.

Developer: Alexey Milovidov.

Fuse GROUP BY with ORDER BY LIMIT

When the GROUP BY key matches the ORDER BY key and the table's
sorting key, the LIMIT is pushed into aggregation-in-order:

SELECT site, avg(dur) FROM visits GROUP BY site ORDER BY site LIMIT 10 SETTINGS optimize_aggregation_in_order = 1; -- stops reading as soon as 10 groups are complete

A test: 200M rows:

26.6: 0.23 sec.
26.7: 0.036 sec. (6.4 times faster!)

Also: DISTINCT in order is 2x faster, LIMIT BY in order 1.4x faster
(faster scanning of runs of equal keys in sorted streams).

Developers: Konstantin Bogdanov, Nihal Z. Miaji.

Query condition cache: more uses

The query condition cache remembers which data ranges matched a WHERE
— now it also works for:

Top-K queries (ORDER BY … LIMIT n) with dynamic filtering —
  including queries with lazy materialization, and entries are shared
  with ordinary queries that have the same WHERE.
Local Parquet files read via the File engine
  (object storage was already supported), keyed by ETag for S3.

Measured — Top-K over 100M rows, second run: 0.114 s → 0.057 s (2x).

Developers: Alexey Milovidov, Shankar Iyer.

Faster formats and compression

Arrow / ArrowStream: a native reader and writer (no Apache Arrow
  library, no extra copies), now the default. Writes ~1.3x faster.

ZSTD decompression on ARM: NEON-vectorized short-offset copies.
  Scan of a repetitive UInt64 column: 3.0 s → 1.8 s (up to 2.3x pure decompression).

GZip via libdeflate: ~1.4–1.5x faster decompression, ~1.15x faster
  compression with a better ratio — for .gz, HTTP, url/s3, Parquet GZIP.

LZ4 decompression is faster for fixed-size, low-cardinality columns.

Delta codec decompression vectorized: 1.5–5x faster.

Developers: Alexey Milovidov, Nikita Taranov, Manuel.

ClickHouse is fast on macOS

A batch of improvements for those who run ClickHouse on a Mac:

— jemalloc no longer purges dirty pages eagerly — a background
  purging thread, like on Linux: allocation-heavy workloads
  (e.g. recursive CTEs) are ~2x faster.

— jemalloc per-CPU arenas and allocation profiling enabled.

— Asynchronous reads from remote replicas (epoll over kqueue) —
  distributed queries read shards in parallel instead of serially.

— SSD cache dictionaries and the FileLog engine now work on macOS.

— STREAM queries are supported.

Developers: Alexey Milovidov, Raúl Marín.

SQL Mandelbrot Benchmark

The Mandelbrot set in pure SQL (a recursive CTE):
github.com/ClickHouse/sql-mandelbrot-benchmark

The Mandelbrot set rendered by ClickHouse in pure SQL

Rendered by ClickHouse.

1ClickHouse (SQL)518 ms
2NumPy (vectorized)688 ms
3chDB (SQL)745 ms
4CedarDB (SQL)835 ms
5ArrowDatafusion (SQL)998 ms
6Arc (DuckDB over HTTP)1,589 ms
7DuckDB (SQL)1,954 ms
11SQLite (SQL)144,421 ms

— The only engine faster than hand-vectorized NumPy.
— MacBook Pro M3 Max — this benchmark surfaced the allocator fix from the previous slide.

Created by Thomas Zeutschler, Ulrich Ludmann, and Jakub Jirak;
continued by Alexey Milovidov.

Faster everything

Faster query analysis: shared subexpressions are not rebuilt when
  constructing the DAG; bounded work for giant AND-chains.

Faster window functions: less memory for SELECT * over wide tables;
  faster quantile*/uniq*/groupArray with OVER () and RANGE frames.

Faster float parsing — and it is precise (closest-representable)
  by default now: 50M floats parse 1.2x faster than 26.6.

Faster uniq, uniqCombined: 500M rows, no keys: 0.23 s → 0.09 s (2.5x).

Redundant logical expressions optimized: a < 3 AND a > 5false,
a = 3 AND a < 5a = 3 — contradictions detected at plan time.

— INTERSECT ALL / EXCEPT ALL are several times faster. And more…

Developers: D. Novik, A. Milovidov, N. Z. Miaji, R. Marín, A. Popov, Xiaozhe Yu.

Even More Interesting

EXPLAIN ANALYZE

Run the query — and see the actual execution metrics in the plan:

EXPLAIN ANALYZE SELECT site, avg(dur) FROM visits WHERE site < 100000 GROUP BY site ORDER BY site LIMIT 10 Query summary: Time: 76.77 ms (planning 29.38 ms · execution 47.39 ms) Read: 20.08 million rows, 160.54 MB (423.72 million rows/s.) Peak memory: 91.95 MiB … └──Aggregating │ I/O: rows 20.00 million → 100.00 thousand (0.50%) · 160 MB → 1.2 MB │ Stage (partial aggregation): time 24.29 ms (51.3%) · parallelism 16.29/96 └──ReadFromMergeTree (default.visits)

— Time split into planning and execution; per-step rows, bytes,
  time share, and achieved parallelism. Find the bottleneck at a glance.

Developer: Kirill Kopnev.

Drivers for UDFs 🧪

Write a UDF in any programming language — right in SQL.
A "driver" compiles it at CREATE time into an executable UDF:

CREATE FUNCTION collatz_steps ARGUMENTS (n UInt64) RETURNS UInt64 ENGINE = GVisorC AS $$ uint64_t steps = 0; while (n > 1) { n = (n % 2 == 0) ? n / 2 : 3 * n + 1; ++steps; } return steps; $$; SELECT number, collatz_steps(number) FROM numbers(1, 10);

— The C body is compiled and runs in sandboxed Docker containers
  the GVisorC, DockerC, and UnsafeC drivers are provided as examples.
— Drivers are declared by the operator; functions survive restarts.

Developers: Daniil Timižev, Alexey Milovidov.

DateTime64: years 0 to 9999

The supported range grew from [1900, 2299]
to [0000-01-01, 9999-12-31]:

SELECT toDateTime64('9999-12-31 23:59:59.999', 3); -- 9999-12-31 23:59:59.999 (was clamped to 2299-12-31) SELECT age('year', toDateTime64('0079-08-24 13:00:00', 0), now()); -- 1946 years since the eruption of Vesuvius SELECT toDateTime64('1789-07-14 12:00:00', 0) + INTERVAL 237 YEAR; -- 2026-07-14 12:00:00

Uses Proleptic Gregorian Calendar.

Developer: Alexey Milovidov.

ZXC codec 🧪

A new asymmetric LZ codec: compresses better than LZ4,
decompresses just as fast
:

CREATE TABLE logs (line String CODEC(ZXC)) …;

codeccompressedratiofull scan
LZ41.28 GiB3.730.21 s
ZXC1.15 GiB4.160.21 s
ZSTD0.67 GiB7.161.05 s

— Compression is slower (~2x LZ4) — by design: pay once on write,
  win on every read. A great fit for read-heavy columns.

Developer: Alexey Milovidov.
ZXC codec: Bertrand Lebonnois and contributors (BSD License) https://github.com/hellobertrand/zxc

SZ3 and ALP codecs

SZ3 🧪 — error-bounded lossy compression for floats:

v Float64 CODEC(SZ3('ALGO_INTERP_LORENZO', 'ABS', 0.001)) -- sensor data, 50M rows: ZSTD 353 MiB → SZ3 22 MiB (16x) -- with the default settings: 2.1 MiB (168x)

ALP 🧪 — now auto-selects between two schemes:

price Float64 CODEC(ALP) -- AUTO: picks STD or RD per block m Float64 CODEC(ALP(RD)) -- force "Real Doubles" -- decimal-like data: ALP ratio 3.74 vs ZSTD 2.42 — and it is lossless

— Both require allow_experimental_codecs = 1.

Developers: Konstantin Vedernikov, Alexey Milovidov, Nazarii Piontko.
SZ3 library: Sheng Di, Kai Zhao, Xin Liang, Jinyang Liu, Franck Cappello, and contributors (BSD License) https://github.com/szcompressor/SZ3
ALP algorithm: Azim Afroozeh, Leonardo Kuffó, and Peter Boncz — CWI (https://ir.cwi.nl/pub/33334)

QueryRunner

A table engine that executes the queries you INSERT into it:

CREATE TABLE shadow (query String) ENGINE = QueryRunner SETTINGS cluster = 'staging', shard = 'random', threads = 4; INSERT INTO shadow SELECT query FROM system.query_log WHERE type = 'QueryFinish'; -- replay production traffic on the staging cluster

— Fire-and-forget: async or sync mode, results are discarded.
— For shadow traffic, benchmarks, fuzzing, batch execution
  of generated queries, and directing queries to remote clusters.
— Access control via SQL SECURITY INVOKER / DEFINER / NONE.

Developer: Miсhael Stetsyuk.

Bonus

WITH 2.5 AS z0, 0.6 AS ty, (24.0, 0.0, 6.0) AS target, (24.0, -45.0, 12.0) AS eye, 36.0 AS fovDeg, getSetting('output_format_image_width')::UInt64 AS W, getSetting('output_format_image_height')::UInt64 AS H, W::Float64 AS imgW, H::Float64 AS imgH, 4 AS maxDepth, (9.0, -30.0, 52.0) AS lightPos, 5.0 AS lightR, (0.42, 0.60, 0.95) AS skyColor, (0.66, 0.78, 0.96) AS hazeColor, 35.0 AS fogStart, 120.0 AS fogRange, (0.02, 0.02, 0.02) AS floorA, (1.00, 0.80, 0.00) AS floorB, 5.0 AS tile, 0.30 AS floorAmb, 0.85 AS floorDiff, (1.0, 1.0, 1.0) AS specColor, 60.0 AS shininess, 0.72 AS reflect_k, (24.0, 12.0, 17.5) AS csgA, 6.0 AS csgAr, (24.0, 6.6, 17.0) AS csgB, 4.4 AS csgBr, 1.15 AS exposure, 2.2 AS gamma, 0.002 AS eps, 48 AS marchSteps, 0.01 AS marchEps, 260.0 AS marchMax, 0.62 AS rodR, [((100000.0,100000.0,100000.0),(1.0,0.0,0.0),(0.0,1.0,0.0),0.1,0.1)] AS oboxes, [((5.75,0.0,2.5),(5.75,0.0,9.5),0.62), ((8.65,0.0,2.5),(8.65,0.0,7.5),0.62), ((16.8,0.0,2.5),(16.8,0.0,9.5),0.62), ((17.15,0.0,5.0),(20.05,0.0,7.6),0.62), ((17.35,0.0,5.1),(20.05,0.0,2.5),0.62), ((22.4,0.0,2.5),(22.4,0.0,9.5),0.62), ((26.15,0.0,2.5),(26.15,0.0,9.5),0.62), ((22.35,0.0,6.0),(26.15,0.0,6.0),0.62), ((34.82,0.0,3.5),(34.82,0.0,7.5),0.62), ((37.72,0.0,3.5),(37.72,0.0,7.5),0.62), ((45.35,0.0,5.05),(48.85,0.0,5.05),0.41333)] AS cyls, [(100000.0,100000.0,0.1,0.05,100000000.0,100000000.0,100000000.0,100000000.0)] AS rings, [((8.65,0.0,8.8),0.72)] AS spheres, [(1.3,6.0,2.28,0.62,(4.425,0.0,6.0),(3.025,100.0,1.5)), (12.95,5.0,1.425,0.575,(16.45,0.0,5.0),(3.4,100.0,1.1)), (30.4,5.0,1.475,0.525,(1000000.0,0.0,1000000.0),(0.1,0.1,0.1)), (36.27,4.0,1.45,0.62,(33.95,0.0,7.75),(9.0,100.0,3.75)), (41.9,6.0,1.025,0.425,(45.375,0.0,-0.25),(3.475,100.0,6.25)), (41.9,3.9,1.025,0.425,(36.375,0.0,7.7),(5.525,100.0,3.8)), (47.25,5.0,1.585,0.465,(50.8,0.0,4.32),(3.25,100.0,0.32))] AS tori, ((a, b) -> tuplePlus(a, b)) AS va, ((a, b) -> tupleMinus(a, b)) AS vs, ((a, s) -> tupleMultiplyByNumber(a, s)) AS vm, ((a, b) -> dotProduct(a, b)) AS vd, ((a) -> L2Normalize(a)) AS vn, ((a, b) -> (a.2*b.3 - a.3*b.2, a.3*b.1 - a.1*b.3, a.1*b.2 - a.2*b.1)) AS vc, ((d, n) -> tupleMinus(d, tupleMultiplyByNumber(n, 2.0 * dotProduct(d, n)))) AS vref, L2Normalize(tupleMinus(target, eye)) AS camFwd, L2Normalize(vc(L2Normalize(tupleMinus(target, eye)), (0.0, 0.0, 1.0))) AS camRight, vc(camRight, camFwd) AS camUp, tan(fovDeg * 0.5 * pi() / 180.0) AS tanHalf, imgW / imgH AS aspect, ((O,D,b) -> arrayMap(eu -> arrayMap(fu -> arrayMap(ev -> arrayMap(fv -> arrayMap(ew -> arrayMap(fw -> arrayMap(lou -> arrayMap(hiu -> arrayMap(lov -> arrayMap(hiv -> arrayMap(low -> arrayMap(hiw -> arrayMap(tn -> arrayMap(tf -> if(tf >= tn AND tf > eps, if(tn > eps, tn, tf), 1e9), [least(hiu, least(hiv, hiw))])[1], [greatest(lou, greatest(lov, low))])[1], [greatest((ew-ty)/fw,(ew+ty)/fw)])[1], [least((ew-ty)/fw,(ew+ty)/fw)])[1], [greatest((ev-b.5)/fv,(ev+b.5)/fv)])[1], [least((ev-b.5)/fv,(ev+b.5)/fv)])[1], [greatest((eu-b.4)/fu,(eu+b.4)/fu)])[1], [least((eu-b.4)/fu,(eu+b.4)/fu)])[1], [D.2])[1], [b.1.2 - O.2])[1], [vd(b.3,D)])[1], [vd(b.3, vs(b.1,O))])[1], [vd(b.2,D)])[1], [vd(b.2, vs(b.1,O))])[1]) AS oboxT, ((hp,b) -> arrayMap(qu -> arrayMap(qv -> arrayMap(qw -> if(abs(qu) >= abs(qv) AND abs(qu) >= abs(qw), vm(b.2, if(qu>0.0,1.0,-1.0)), if(abs(qv) >= abs(qw), vm(b.3, if(qv>0.0,1.0,-1.0)), (0.0, if(qw>0.0,1.0,-1.0), 0.0))), [(hp.2 - b.1.2)/ty])[1], [vd(b.3, vs(hp,b.1))/b.5])[1], [vd(b.2, vs(hp,b.1))/b.4])[1]) AS oboxN, ((O,D,A,B,r) -> arrayMap(ba -> arrayMap(oa -> arrayMap(baba -> arrayMap(bard -> arrayMap(baoa -> arrayMap(aa -> arrayMap(bb -> arrayMap(cc -> arrayMap(hh -> arrayMap(t -> arrayMap(y -> if(hh >= 0.0 AND aa > 1e-9 AND t > eps AND y > 0.0 AND y < baba, t, 1e9), [baoa + t*bard])[1], [(-bb - sqrt(greatest(hh,0.0)))/aa])[1], [bb*bb - aa*cc])[1], [baba*vd(oa,oa) - baoa*baoa - r*r*baba])[1], [baba*vd(D,oa) - baoa*bard])[1], [baba - bard*bard])[1], [vd(ba,oa)])[1], [vd(ba,D)])[1], [vd(ba,ba)])[1], [vs(O,A)])[1], [vs(B,A)])[1]) AS cylBodyT, ((O,D,P,ax,r) -> arrayMap(den -> arrayMap(t -> arrayMap(hp -> if(abs(den) > 1e-9 AND t > eps AND vd(vs(hp,P), vs(hp,P)) <= r*r, t, 1e9), [va(O, vm(D, t))])[1], [vd(ax, vs(P,O))/den])[1], [vd(ax, D)])[1]) AS diskT, ((O,D,A,B,r) -> least(cylBodyT(O,D,A,B,r), least(diskT(O,D,A,vs(B,A),r), diskT(O,D,B,vs(B,A),r)))) AS rodT, ((O,D,A,B,r) -> arrayMap(ba -> arrayMap(tL -> arrayMap(tA -> arrayMap(tB -> arrayMap(tm -> arrayMap(hp -> if(tm = tL, vn(vs(hp, va(A, vm(ba, vd(vs(hp,A),ba)/vd(ba,ba))))), if(tm = tA, vn(vm(ba,-1.0)), vn(ba))), [va(O, vm(D,tm))])[1], [least(tL, least(tA,tB))])[1], [diskT(O,D,B,ba,r)])[1], [diskT(O,D,A,ba,r)])[1], [cylBodyT(O,D,A,B,r)])[1], [vs(B,A)])[1]) AS rodN, ((O,D,rg) -> arrayMap(a2 -> arrayMap(hb -> arrayMap(rr -> arrayMap(dO -> arrayMap(dI -> arrayMap(toN -> arrayMap(toF -> arrayMap(tiN -> arrayMap(tiF -> arrayMap(ty0 -> arrayMap(ty1 -> arrayMap(tcN -> arrayMap(tcF -> arrayMap(aN -> arrayMap(aF -> arrayMap(e1 -> arrayMap(e2 -> arrayMap(e3 -> arrayMap(tm -> tm, [least(e1, least(e2, e3))])[1], [if(aN < tcF AND tcF < aF AND tcF > eps AND NOT (tiN < tcF AND tcF < tiF), tcF, 1e9)])[1], [if(aN < tiF AND tiF < aF AND tiF > eps AND NOT (tcN < tiF AND tiF < tcF), tiF, 1e9)])[1], [if(aN < aF AND aN > eps AND NOT (tiN < aN AND aN < tiF) AND NOT (tcN < aN AND aN < tcF), aN, 1e9)])[1], [least(ty1, toF)])[1], [greatest(ty0, toN)])[1], [least(greatest((rg.5-O.1)/D.1,(rg.7-O.1)/D.1), greatest((rg.6-O.3)/D.3,(rg.8-O.3)/D.3))])[1], [greatest(least((rg.5-O.1)/D.1,(rg.7-O.1)/D.1), least((rg.6-O.3)/D.3,(rg.8-O.3)/D.3))])[1], [greatest((-ty-O.2)/D.2, (ty-O.2)/D.2)])[1], [least((-ty-O.2)/D.2, (ty-O.2)/D.2)])[1], [if(dI > 0.0, (-hb + sqrt(dI))/a2, -1e9)])[1], [if(dI > 0.0, (-hb - sqrt(dI))/a2, 1e9)])[1], [if(dO > 0.0, (-hb + sqrt(dO))/a2, -1e9)])[1], [if(dO > 0.0, (-hb - sqrt(dO))/a2, 1e9)])[1], [hb*hb - a2*(rr - rg.4*rg.4)])[1], [hb*hb - a2*(rr - rg.3*rg.3)])[1], [(O.1-rg.1)*(O.1-rg.1) + (O.3-rg.2)*(O.3-rg.2)])[1], [(O.1-rg.1)*D.1 + (O.3-rg.2)*D.3])[1], [greatest(D.1*D.1 + D.3*D.3, 1e-12)])[1]) AS ringT, ((O,D,rg) -> arrayMap(a2 -> arrayMap(hb -> arrayMap(rr -> arrayMap(dO -> arrayMap(dI -> arrayMap(toN -> arrayMap(toF -> arrayMap(tiN -> arrayMap(tiF -> arrayMap(ty0 -> arrayMap(ty1 -> arrayMap(tcN -> arrayMap(tcF -> arrayMap(aN -> arrayMap(aF -> arrayMap(e1 -> arrayMap(e2 -> arrayMap(e3 -> arrayMap(tm -> arrayMap(hp -> if(tm = e1, if(toN >= ty0, vn((hp.1-rg.1, 0.0, hp.3-rg.2)), (0.0, if(D.2>0.0,-1.0,1.0), 0.0)), if(tm = e2, vn((rg.1-hp.1, 0.0, rg.2-hp.3)), if(greatest((rg.5-O.1)/D.1,(rg.7-O.1)/D.1) <= greatest((rg.6-O.3)/D.3,(rg.8-O.3)/D.3), (if(D.1>0.0,-1.0,1.0),0.0,0.0), (0.0,0.0,if(D.3>0.0,-1.0,1.0))))), [va(O, vm(D, tm))])[1], [least(e1, least(e2, e3))])[1], [if(aN < tcF AND tcF < aF AND tcF > eps AND NOT (tiN < tcF AND tcF < tiF), tcF, 1e9)])[1], [if(aN < tiF AND tiF < aF AND tiF > eps AND NOT (tcN < tiF AND tiF < tcF), tiF, 1e9)])[1], [if(aN < aF AND aN > eps AND NOT (tiN < aN AND aN < tiF) AND NOT (tcN < aN AND aN < tcF), aN, 1e9)])[1], [least(ty1, toF)])[1], [greatest(ty0, toN)])[1], [least(greatest((rg.5-O.1)/D.1,(rg.7-O.1)/D.1), greatest((rg.6-O.3)/D.3,(rg.8-O.3)/D.3))])[1], [greatest(least((rg.5-O.1)/D.1,(rg.7-O.1)/D.1), least((rg.6-O.3)/D.3,(rg.8-O.3)/D.3))])[1], [greatest((-ty-O.2)/D.2, (ty-O.2)/D.2)])[1], [least((-ty-O.2)/D.2, (ty-O.2)/D.2)])[1], [if(dI > 0.0, (-hb + sqrt(dI))/a2, -1e9)])[1], [if(dI > 0.0, (-hb - sqrt(dI))/a2, 1e9)])[1], [if(dO > 0.0, (-hb + sqrt(dO))/a2, -1e9)])[1], [if(dO > 0.0, (-hb - sqrt(dO))/a2, 1e9)])[1], [hb*hb - a2*(rr - rg.4*rg.4)])[1], [hb*hb - a2*(rr - rg.3*rg.3)])[1], [(O.1-rg.1)*(O.1-rg.1) + (O.3-rg.2)*(O.3-rg.2)])[1], [(O.1-rg.1)*D.1 + (O.3-rg.2)*D.3])[1], [greatest(D.1*D.1 + D.3*D.3, 1e-12)])[1]) AS ringN, ((O,D,C,r) -> if(dotProduct(vs(O,C),D)*dotProduct(vs(O,C),D) - (dotProduct(vs(O,C),vs(O,C))-r*r) > 0.0 AND -dotProduct(vs(O,C),D) - sqrt(greatest(dotProduct(vs(O,C),D)*dotProduct(vs(O,C),D)-(dotProduct(vs(O,C),vs(O,C))-r*r),0.0)) > eps, -dotProduct(vs(O,C),D) - sqrt(greatest(dotProduct(vs(O,C),D)*dotProduct(vs(O,C),D)-(dotProduct(vs(O,C),vs(O,C))-r*r),0.0)), 1e9)) AS sphT, ((o, d, c, rad) -> if( dotProduct(vs(o,c), d) * dotProduct(vs(o,c), d) - (dotProduct(vs(o,c), vs(o,c)) - rad*rad) > 0.0, (-dotProduct(vs(o,c), d) - sqrt(greatest(dotProduct(vs(o,c), d) * dotProduct(vs(o,c), d) - (dotProduct(vs(o,c), vs(o,c)) - rad*rad), 0.0)), -dotProduct(vs(o,c), d) + sqrt(greatest(dotProduct(vs(o,c), d) * dotProduct(vs(o,c), d) - (dotProduct(vs(o,c), vs(o,c)) - rad*rad), 0.0))), (1e9, -1e9))) AS sphPair, ((p,tl) -> sqrt(pow(sqrt((p.1-tl.1)*(p.1-tl.1)+(p.3-tl.2)*(p.3-tl.2)) - tl.3, 2) + p.2*p.2) - tl.4) AS tsdf, ((p,C,H) -> sqrt(pow(greatest(abs(p.1-C.1)-H.1,0.0),2) + pow(greatest(abs(p.2-C.2)-H.2,0.0),2) + pow(greatest(abs(p.3-C.3)-H.3,0.0),2)) + least(greatest(abs(p.1-C.1)-H.1, greatest(abs(p.2-C.2)-H.2, abs(p.3-C.3)-H.3)), 0.0)) AS bsdf, ((p) -> arrayMin(arrayMap(tl -> greatest(tsdf(p, tl), -bsdf(p, tl.5, tl.6)), tori))) AS toriSDF, ((O,D) -> arrayMap(tfin -> if(toriSDF(va(O, vm(D, tfin))) < marchEps AND tfin > eps AND tfin < marchMax, tfin, 1e9), [arrayFold((t, i) -> t + toriSDF(va(O, vm(D, t))), range(marchSteps), 0.02)])[1]) AS marchTorus, ((O,D,t) -> arrayMap(p -> vn(va(va(vm((1.0,-1.0,-1.0), toriSDF(va(p, (0.0009,-0.0009,-0.0009)))), vm((-1.0,-1.0,1.0), toriSDF(va(p, (-0.0009,-0.0009,0.0009))))), va(vm((-1.0,1.0,-1.0), toriSDF(va(p, (-0.0009,0.0009,-0.0009)))), vm((1.0,1.0,1.0), toriSDF(va(p, (0.0009,0.0009,0.0009))))))), [va(O, vm(D, t))])[1]) AS torusN, ((o, d) -> if(d.3 < -eps AND o.3 > 0.0, -o.3 / d.3, 1e9)) AS planeT, ((o, d, maxd) -> arrayExists(b -> oboxT(o, d, b) < maxd, oboxes) OR arrayExists(c -> rodT(o, d, c.1, c.2, c.3) < maxd, cyls) OR arrayExists(rg -> ringT(o, d, rg) < maxd, rings) OR arrayExists(sp -> sphT(o, d, sp.1, sp.2) < maxd, spheres) OR (marchTorus(o, d) < maxd)) AS occluded, ((d) -> tupleMultiplyByNumber(skyColor, 0.35 + 0.65 * pow(greatest(1.0 - d.3, 0.0), 3.0))) AS sky, ((p) -> (toInt64(floor(p.1 / tile)) + toInt64(floor(p.2 / tile))) % 2) AS checker, ((a, b, c) -> (cityHash64(a, b, c) % 1048576) / 1048576.0) AS rnd, ((s, lpos) -> arrayMap(o -> arrayMap(d -> arrayMap(thr -> arrayMap(acc -> arrayMap(oboxHits -> arrayMap(cylHits -> arrayMap(ringHits -> arrayMap(sphHits -> arrayMap(tTorus -> arrayMap(tBox -> arrayMap(tCyl -> arrayMap(tRing -> arrayMap(tSph -> arrayMap(tLet -> arrayMap(tP -> arrayMap(pairA -> arrayMap(pairB -> arrayMap(cEnter -> arrayMap(cCav -> arrayMap(tC -> arrayMap(tM -> arrayMap(tHit -> arrayMap(hp -> arrayMap(letN -> arrayMap(sn -> arrayMap(isMirror -> arrayMap(isFloor -> arrayMap(isMiss -> arrayMap(nrm -> arrayMap(shOrig -> arrayMap(rdir -> arrayMap(ldir -> arrayMap(distL -> arrayMap(shadowed -> arrayMap(spec -> arrayMap(lambert -> arrayMap(fog -> arrayMap(floorCol -> ( if(isMirror, shOrig, o), if(isMirror, rdir, d), if(isMirror, thr * reflect_k, thr), va(acc, va(if(isMirror, vm(specColor, thr * spec), (0.0, 0.0, 0.0)), va(if(isFloor, vm(floorCol, thr), (0.0, 0.0, 0.0)), if(isMiss, vm(sky(d), thr), (0.0, 0.0, 0.0))))), if(isMirror, 1.0, 0.0)), [va(vm(vm(if(checker(hp) = 0, floorA, floorB), floorAmb + floorDiff * lambert), 1.0 - fog), vm(hazeColor, fog))])[1], [least(1.0, greatest(0.0, (tHit - fogStart) / fogRange))])[1], [greatest(vd(ldir, (0.0, 0.0, 1.0)), 0.0) * if(shadowed, 0.0, 1.0)])[1], [pow(greatest(vd(ldir, rdir), 0.0), shininess) * if(shadowed, 0.0, 1.0)])[1], [occluded(shOrig, ldir, distL - 0.05)])[1], [L2Norm(vs(lpos, hp))])[1], [vn(vs(lpos, hp))])[1], [vref(d, sn)])[1], [va(hp, vm(nrm, eps * 2.0))])[1], [if(isFloor, (0.0, 0.0, 1.0), sn)])[1], [(tM >= 1e8) AND (tP >= 1e8)])[1], [(tP <= tM) AND (tP < 1e8)])[1], [(tM < tP) AND (tM < 1e8)])[1], [if(tC < tLet, if(cEnter <= cCav, vn(vs(hp, csgA)), vn(vs(csgB, hp))), letN)])[1], [if(tTorus <= tBox AND tTorus <= tCyl AND tTorus <= tRing AND tTorus <= tSph, torusN(o, d, tTorus), if(tCyl <= tBox AND tCyl <= tRing AND tCyl <= tSph, rodN(o, d, cyls[indexOf(cylHits, tCyl)].1, cyls[indexOf(cylHits, tCyl)].2, cyls[indexOf(cylHits, tCyl)].3), if(tBox <= tRing AND tBox <= tSph, oboxN(hp, oboxes[indexOf(oboxHits, tBox)]), if(tRing <= tSph, ringN(o, d, rings[indexOf(ringHits, tRing)]), vn(vs(hp, spheres[indexOf(sphHits, tSph)].1))))))])[1], [va(o, vm(d, tHit))])[1], [least(tM, tP)])[1], [least(tLet, tC)])[1], [least(cEnter, cCav)])[1], [if(pairB.1 < 1e8 AND pairB.2 > eps AND pairA.1 <= pairB.2 AND pairB.2 <= pairA.2, pairB.2, 1e9)])[1], [if(pairA.1 > eps AND pairA.1 < 1e8 AND NOT (pairB.1 <= pairA.1 AND pairA.1 <= pairB.2), pairA.1, 1e9)])[1], [sphPair(o, d, csgB, csgBr)])[1], [sphPair(o, d, csgA, csgAr)])[1], [planeT(o, d)])[1], [least(least(tBox, tCyl), least(tRing, least(tSph, tTorus)))])[1], [arrayMin(sphHits)])[1], [arrayMin(ringHits)])[1], [arrayMin(cylHits)])[1], [arrayMin(oboxHits)])[1], [marchTorus(o, d)])[1], [arrayMap(sp -> sphT(o, d, sp.1, sp.2), spheres)])[1], [arrayMap(rg -> ringT(o, d, rg), rings)])[1], [arrayMap(c -> rodT(o, d, c.1, c.2, c.3), cyls)])[1], [arrayMap(b -> oboxT(o, d, b), oboxes)])[1], [s.4])[1], [s.3])[1], [s.2])[1], [s.1])[1]) AS oneBounce SELECT clamp(pow(greatest(avg(col.1), 0.0) * exposure, 1.0 / gamma), 0.0, 1.0) AS r, clamp(pow(greatest(avg(col.2), 0.0) * exposure, 1.0 / gamma), 0.0, 1.0) AS g, clamp(pow(greatest(avg(col.3), 0.0) * exposure, 1.0 / gamma), 0.0, 1.0) AS b, pixel % W AS x, intDiv(pixel, W) AS y FROM ( SELECT pixel, va(st.4, if(st.5 > 0.5, vm(sky(st.2), st.3), (0.0,0.0,0.0))) AS col FROM ( SELECT pixel, arrayFold((s, i) -> if(s.5 > 0.5, oneBounce(s, lpos), s), range(maxDepth), st0) AS st FROM ( SELECT intDiv(number, {SAMPLES:UInt32}) AS pixel, number % {SAMPLES:UInt32} AS sample, va(lightPos, (lightR * (rnd(pixel, sample, 3) - 0.5), lightR * (rnd(pixel, sample, 4) - 0.5), lightR * (rnd(pixel, sample, 5) - 0.5))) AS lpos, CAST((eye, vn(va(camFwd, va(vm(camRight, (((pixel % W) + rnd(pixel, sample, 1)) / imgW * 2.0 - 1.0) * aspect * tanHalf), vm(camUp, (1.0 - (intDiv(pixel, W) + rnd(pixel, sample, 2)) / imgH * 2.0) * tanHalf)))), 1.0, (0.0, 0.0, 0.0), 1.0) AS Tuple(Tuple(Float64,Float64,Float64), Tuple(Float64,Float64,Float64), Float64, Tuple(Float64,Float64,Float64), Float64)) AS st0 FROM numbers_mt(W * H * {SAMPLES:UInt32}) ) ) ) GROUP BY pixel SETTINGS max_block_size = 2048 FORMAT PNG

RayTracer — a ray tracer in ClickHouse SQL

github.com/ClickHouse/RayTracer

ClickHouse rendered as chrome CSG letters over a procedural terrain, ray-traced in SQL
rowsandcolumnssummit.com

Open House World Tour

Open House by ClickHouse — the real-time database for AI conference

🇦🇺 Sydney, Aug 11  ·  🇦🇺 Melbourne, Aug 13  ·  🇳🇱 Amsterdam, Sep 1
🇺🇸 New York, Sep 10  ·  🇮🇳 Bangalore, Sep 22  ·  🇸🇬 Singapore, Sep 24
🇬🇧 London, Sep 30  ·  🇩🇪 Munich, Oct 6

Meetups


— 🇹🇭 Bangkok: OSS & Data Evening, Jul 23
— 🇮🇳 Mumbai: Lakes to Queries, Jul 25
— 🇸🇬 Singapore: BUILD Workshop, Jul 28
— 🇯🇵 Tokyo: Google Cloud Next, Jul 30
— 🇨🇴 Bogotá: AWS Summit, Jul 30
— 🇮🇩 Jakarta Meetup, Aug 5
— 🇺🇸 Seattle: AI Demo Night, Aug 6
— 🇨🇱 Santiago: Real-time Analytics Training, Aug 6
— 🇺🇸 San Francisco Meetup, Aug 11
— 🇦🇺 Sydney User Conference, Aug 11
— 🇦🇺 Melbourne User Conference, Aug 13
— 🇺🇸 New York: AI Demo Night, Aug 18

Reading Corner 📖

QR: clickhouse.com/blog/introducing-the-clickhouse-adbc-driver

https://clickhouse.com/blog/

— A Quadrillion Rows across three Clouds: scaling LogHouse
— One driver, one format, every language: ADBC
— chDB as the Agent's Local Data Engine
— Replacing the HDB: ClickHouse for historical ticker data
— Introducing pg_re2, fast, RE2-powered regular expressions in Postgres
— How we made ClickStack 5x faster for ClickHouse observability
— ClickHouse on Docker Hardened Images
— How we scale PgBouncer in ClickHouse Managed Postgres
— @clickhouse/rowbinary: when your library is also a parser compiler

Q&A