04 Jalankan kueri pasar
Tujuh kueri terhadap 26.5M tick, masing-masing menggantikan satu halaman SQL: hitungan aproksimasi, topK, candlestick OHLC, persentil, kombinator -If, argMax, dan finale sort key.
Inilah "fungsi-fungsi yang menggantikan satu halaman SQL" milik ClickHouse. Tempelkan setiap blok,
jalankan, lalu baca kotak hijaunya untuk mengetahui apa yang diharapkan. Semuanya berjalan terhadap
tabel forex yang baru saja Anda muat.
4.1 Aproksimasi vs eksak — trik utamanya
Ada berapa timestamp quote yang distinct di dalam 26.5M tick? Tiga fungsi menjawab pertanyaan yang sama dengan trade-off berbeda. Jalankan satu per satu dan perhatikan timer di statistik kueri — menjalankannya secara terpisah justru itulah intinya.
-- Approximate count of distinct timestamps (HyperLogLog)
SELECT uniq(datetime) AS distinct_ts FROM forex;-- Exact count — precise, but scans every value
SELECT uniqExact(datetime) AS distinct_ts FROM forex;-- Adaptive + tunable accuracy vs memory
SELECT uniqCombined(datetime) AS distinct_ts FROM forex;Yang seharusnya Anda lihat
Sekitar 24.6 juta timestamp distinct dari ketiganya. Tetapi uniq kembali dalam ~0.2 s,
uniqExact butuh ~3 s (sekitar 17× lebih lambat) untuk angka yang presisi, dan
uniqCombined mendarat dalam ~0.4% jauh di bawah satu detik. Pada skala miliaran baris, selisih
itu adalah perbedaan antara instan dan rehat ngopi.
4.2 Top-N dalam satu fungsi
Pasangan yang paling aktif dikutip — tanpa perlu GROUP BY / ORDER BY / LIMIT:
-- One row: an array of the 8 most actively quoted pairs (by tick count)
SELECT topK(8)(pair) AS most_active FROM forex;Yang seharusnya Anda lihat
Satu sel berisi array 8 pasangan, yang paling banyak dikutip lebih dulu (emas, XAU/USD,
memuncaki daftar). topK meringkas seluruh tabel menjadi daftar berperingkat itu dalam satu
lintasan — ia menggantikan GROUP BY … ORDER BY count() DESC LIMIT 8.
4.3 Time-series dalam satu lintasan — candlestick OHLC
Open / high / low / close harian untuk emas — kueri pasar yang paling sehari-hari:
-- One row per day: gold (XAU/USD) open, high, low, close — a candlestick chart
SELECT
toDate(datetime) AS day,
argMin(bid, datetime) AS open, -- bid at the day's first tick
max(bid) AS high,
min(bid) AS low,
argMax(bid, datetime) AS close -- bid at the day's last tick
FROM forex
WHERE base = 'XAU' AND quote = 'USD'
GROUP BY day
ORDER BY day;Yang seharusnya Anda lihat
Satu baris per hari untuk Januari 2020. argMin(bid, datetime) adalah bid pada tick pertama
hari itu (open) dan argMax pada tick terakhir (close) — tanpa window function, tanpa
self-join. Perhatikan emas menanjak dari ~1,520 ke ~1,610 sepanjang bulan itu.
4.4 Persentil tanpa akrobat window
Bid/ask spread adalah pengukur likuiditas — dan rata-rata menyembunyikan ekornya, jadi pakai persentil:
-- One row per pair: median and 99th-percentile bid/ask spread (tighter = more liquid)
SELECT
pair,
round(quantile(0.5)(ask - bid), 6) AS median_spread,
round(quantile(0.99)(ask - bid), 6) AS p99_spread
FROM forex
GROUP BY pair
ORDER BY median_spread ASC;Yang seharusnya Anda lihat
Satu baris per pasangan, spread terketat lebih dulu. EUR/USD keluar sebagai yang paling
likuid (~0.00002, sub-pip); emas yang terlebar. quantile dihitung secara aproksimatif dalam
satu lintasan — tanpa mengurutkan seluruh kolom.
4.5 Kombinator — satu scan, dua jawaban
Rata-rata spread pada jam perdagangan aktif vs jam sepi, berdampingan, dalam satu scan:
-- One row per pair: avg spread during the active window vs quiet hours
SELECT
pair,
count() AS ticks,
round(avgIf(ask - bid, toHour(datetime) BETWEEN 7 AND 20), 6) AS spread_active,
round(avgIf(ask - bid, toHour(datetime) NOT BETWEEN 7 AND 20), 6) AS spread_quiet
FROM forex
GROUP BY pair
ORDER BY ticks DESC;Yang seharusnya Anda lihat
Spread pada jendela aktif dan jam sepi dalam hasil yang sama. Kombinator -If memasang sebuah
kondisi pada agregat apa pun: avgIf(x, cond) merata-ratakan x hanya ketika cond benar —
tanpa kueri dua lintasan, tanpa CASE WHEN. Hampir setiap agregat menerimanya (countIf,
sumIf, quantileIf, …).
4.6 Nilai terbaru — argMax
Quote terbaru untuk setiap pasangan, dalam satu lintasan:
-- One row per pair: the latest quoted bid and the timestamp it was seen
SELECT
pair,
argMax(bid, datetime) AS last_bid,
max(datetime) AS as_of
FROM forex
GROUP BY pair
ORDER BY pair;Yang seharusnya Anda lihat
Bid terbaru per pasangan. argMax(bid, datetime) mengembalikan bid dari baris dengan
datetime terbesar — kueri "harga terakhir / status terbaru" yang lazim sehari-hari, tanpa
window function atau self-join.
4.7 Finale — sort key vs tanpa sort key
Bentuk kueri yang sama — menghitung tick yang memenuhi sebuah kondisi — tetapi satu filter mengenai sort key dan satunya tidak. Pertama, jalankan kedua hitungan:
-- Optimized: base+quote ARE the leading sort key — the index skips to that pair
SELECT count() FROM forex WHERE base = 'XAU' AND quote = 'USD';
-- Non-optimized: bid is NOT in the sort key — no index, scans all 26.5M ticks.
-- (cache off so the full scan shows on every run)
SELECT count() FROM forex WHERE bid > 1.5
SETTINGS use_query_condition_cache = 0;Sulit melihat bedanya?
Kedua hitungan kembali dalam beberapa milidetik, jadi dari waktunya saja nyaris tidak terlihat
bergerak — count() memang cepat dengan cara mana pun. Perbedaan sebenarnya adalah seberapa
banyak data yang harus disentuh masing-masing. Untuk benar-benar melihatnya, minta ClickHouse
menunjukkan rencananya dengan EXPLAIN indexes = 1, yang melaporkan berapa banyak granule
(blok ~8,192 baris) yang akan dibaca.
-- Optimized: the primary index skips straight to the XAU/USD rows
EXPLAIN indexes = 1
SELECT count() FROM forex WHERE base = 'XAU' AND quote = 'USD';
-- Non-optimized: bid isn't in the sort key, so nothing can be skipped
EXPLAIN indexes = 1
SELECT count() FROM forex WHERE bid > 1.5;Yang seharusnya Anda lihat
Pada rencana yang teroptimasi, bagian Indexes → PrimaryKey menunjukkan hanya sebagian
granule yang dipilih — sekitar 492 / 3,234 (~16K baris). Pada rencana yang tidak
teroptimasi tidak ada index yang bisa diterapkan, jadi ia membaca 3,234 / 3,234 granule —
setiap baris tanpa terkecuali. Bentuk kueri yang sama, beban kerja yang jauh berbeda.
Pelajarannya: letakkan kolom yang paling sering Anda filter di depan ORDER BY Anda.
Simpan yang satu ini di clipboard Anda
Anda akan menyerahkan kueri WHERE bid > 1.5 yang tidak teroptimasi itu ke AI pada
modul berikutnya.
03 Muat data — dua cara
26.5M tick yang sama dimuat dua kali: ClickPipes, pipeline terkelola yang akan Anda pakai di produksi, lalu one-liner s3() — dan kapan memilih yang mana.
05 Minta AI memperbaiki kueri
Serahkan kueri full-scan dari modul 04 ke ClickHouse Assistant dan lihat ia mendiagnosis sort key yang hilang, lalu menawarkan skip index dan projection lengkap dengan SQL siap jalan.