Real-Time Market AnalyticsClickHouse Workshops

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.

Di halaman ini

Track your progress?

Optional. We email a link to confirm your address; progress records once you open it.

Please use your work email address, not a personal one.

Progress tracking also requires accepting the current Terms of Service in Privacy settings.

ID