<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts on QuestDB Lab — Independent QuestDB Technical Blog</title><link>https://questdblab.org/en/post/</link><description>Recent content in Posts on QuestDB Lab — Independent QuestDB Technical Blog</description><generator>Hugo -- gohugo.io</generator><language>en-US</language><lastBuildDate>Tue, 13 Oct 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://questdblab.org/en/post/index.xml" rel="self" type="application/rss+xml"/><item><title>QuestDB vs DuckDB: Both Are 'Fast and Light' — Why Time-Series Belongs in QuestDB</title><link>https://questdblab.org/en/post/questdb-vs-duckdb-chinese/</link><pubDate>Tue, 13 Oct 2026 00:00:00 +0000</pubDate><guid>https://questdblab.org/en/post/questdb-vs-duckdb-chinese/</guid><description>&lt;h1 id="questdb-vs-duckdb-both-are-fast-and-light--why-time-series-belongs-in-questdb"&gt;QuestDB vs DuckDB: Both Are &amp;ldquo;Fast and Light&amp;rdquo; — Why Time-Series Belongs in QuestDB
&lt;/h1&gt;&lt;p&gt;If you know DuckDB well, you&amp;rsquo;ve probably heard QuestDB&amp;rsquo;s name in the same breath — it&amp;rsquo;s often compared alongside DuckDB, ClickHouse, and InfluxDB. The instinct reaction is: &amp;ldquo;Aren&amp;rsquo;t they both columnar and fast? Does it matter which one I pick?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It matters a lot. They are two different species.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The cost of a wrong pick isn&amp;rsquo;t &amp;ldquo;a bit slower&amp;rdquo; — it&amp;rsquo;s &amp;ldquo;the whole architecture has to be redone.&amp;rdquo; This post breaks down QuestDB vs DuckDB with 2026-10 single-node measurements, answering one question: &lt;strong&gt;is your data ready for QuestDB?&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="the-one-line-verdict"&gt;The One-Line Verdict
&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;What your data looks like&lt;/th&gt;
 &lt;th&gt;Pick&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Second-level, continuously-arriving&lt;/strong&gt; time series (IoT / monitoring / financial tick / logs)&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;QuestDB&lt;/strong&gt; ✅&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;One-shot analysis of existing files&lt;/strong&gt; (CSV / Parquet / Excel, GB-scale)&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;DuckDB&lt;/strong&gt; ✅&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;The core distinction in one line: DuckDB is an embedded analytics engine you &amp;ldquo;feed it files&amp;rdquo;; QuestDB is a time-series database that &amp;ldquo;consumes a stream.&amp;rdquo;&lt;/strong&gt; One is &lt;code&gt;read_parquet()&lt;/code&gt;, the other is millions of rows per second over ILP — different lanes.&lt;/p&gt;
&lt;h2 id="2-the-core-difference-the-root-of-selection"&gt;2. The Core Difference (the root of selection)
&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Dimension&lt;/th&gt;
 &lt;th&gt;QuestDB&lt;/th&gt;
 &lt;th&gt;DuckDB&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Positioning&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Time-series database&lt;/td&gt;
 &lt;td&gt;Embedded OLAP engine&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Deployment&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Standalone service (Docker/K8s)&lt;/td&gt;
 &lt;td&gt;In-process library (like SQLite)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;External deps&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;None (pure JVM)&lt;/td&gt;
 &lt;td&gt;None (pure C++)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Primary write path&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;High-throughput ILP streaming&lt;/td&gt;
 &lt;td&gt;Reads existing files&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Transactions&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;No (time-series append-only)&lt;/td&gt;
 &lt;td&gt;Full ACID&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Typical scale&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;100k–1M rows/sec&lt;/td&gt;
 &lt;td&gt;Single file GB–tens of GB&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The key line:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;QuestDB = &amp;ldquo;write-heavy, read-fast time-series&amp;rdquo;&lt;/strong&gt; — built for continuous high-speed ingest;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DuckDB = &amp;ldquo;the analytics engine embedded in your process&amp;rdquo;&lt;/strong&gt; — it basically doesn&amp;rsquo;t &amp;ldquo;consume a stream&amp;rdquo;; you feed it files.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="3-four-dimensions-measured-2026-10-4c8g-single-node-docker"&gt;3. Four Dimensions, Measured (2026-10, 4C8G single node, Docker)
&lt;/h2&gt;&lt;p&gt;Ingest dataset: 100M CPU metric rows (~80 bytes each, ~8GB).&lt;/p&gt;
&lt;h3 id="31-write-throughput"&gt;3.1 Write Throughput
&lt;/h3&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;System&lt;/th&gt;
 &lt;th&gt;Method&lt;/th&gt;
 &lt;th&gt;Measured&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;QuestDB&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;ILP TCP batch&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;~520,000 rows/s&lt;/strong&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;DuckDB&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;COPY from CSV/Parquet&lt;/td&gt;
 &lt;td&gt;One-shot file load, not streaming&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;QuestDB&amp;rsquo;s design goal is &lt;strong&gt;second-level high-speed streams&lt;/strong&gt;; DuckDB basically doesn&amp;rsquo;t compete in this lane (it wasn&amp;rsquo;t designed to ingest a stream). If your data is sensors reporting every second or high-frequency ticks, only QuestDB can keep up.&lt;/p&gt;
&lt;h3 id="32-time-series-aggregation"&gt;3.2 Time-Series Aggregation
&lt;/h3&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;System&lt;/th&gt;
 &lt;th&gt;100M rows, &amp;ldquo;aggregate 1 day by 1m&amp;rdquo;&lt;/th&gt;
 &lt;th&gt;P50&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;QuestDB&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;native &lt;code&gt;SAMPLE BY 1m&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;~2ms&lt;/strong&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;DuckDB&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;needs &lt;code&gt;make_time_bucket&lt;/code&gt; UDF&lt;/td&gt;
 &lt;td&gt;~40ms&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;SAMPLE BY&lt;/code&gt; / &lt;code&gt;FIRST&lt;/code&gt; / &lt;code&gt;LATEST&lt;/code&gt; are &lt;strong&gt;first-class time-series syntax&lt;/strong&gt; in QuestDB; DuckDB has to emulate with plain SQL + a UDF. That&amp;rsquo;s a species difference, not something tuning closes.&lt;/p&gt;
&lt;h3 id="33-deployment--ops"&gt;3.3 Deployment &amp;amp; Ops
&lt;/h3&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;System&lt;/th&gt;
 &lt;th&gt;Complexity&lt;/th&gt;
 &lt;th&gt;Notes&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;DuckDB&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;⭐ lowest&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;import duckdb&lt;/code&gt; and you&amp;rsquo;re in; zero ops&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;QuestDB&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;⭐⭐ low&lt;/td&gt;
 &lt;td&gt;one container, but you have to think &amp;ldquo;service&amp;rdquo;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="34-ecosystem"&gt;3.4 Ecosystem
&lt;/h3&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;System&lt;/th&gt;
 &lt;th&gt;Strength&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;QuestDB&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Native Grafana data source, Prometheus direct write, time-series SQL&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;DuckDB&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Query Parquet/Iceberg directly, embed in Python/JS in one line, cross data lake&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="4-when-would-you-use-both"&gt;4. When Would You Use &amp;ldquo;Both&amp;rdquo;?
&lt;/h2&gt;&lt;p&gt;In real production the two &lt;strong&gt;can coexist&lt;/strong&gt;, with clean separation of duties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;QuestDB&lt;/strong&gt; ingests the real-time stream (sensors / metrics / logs / tick)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DuckDB&lt;/strong&gt; runs offline deep analysis over Parquet data lakes, one-shot jobs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Don&amp;rsquo;t try to replace one with the other — that&amp;rsquo;s not cost savings, that&amp;rsquo;s digging a hole.&lt;/p&gt;
&lt;h2 id="5-decision-tree-copy-paste"&gt;5. Decision Tree (copy-paste)
&lt;/h2&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Is your data &amp;#34;continuously arriving every second&amp;#34;?
├─ yes → Is it time-series / metrics / logs / financial tick?
│ ├─ yes → QuestDB ✅
│ └─ no (high-concurrency OLTP) → use Postgres, not these two
└─ no (you have files: CSV/Parquet/Excel)
 └─ embed in your program, no service → DuckDB ✅
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="6-common-mistakes-from-people-crossing-over-from-the-duckdb-world"&gt;6. Common Mistakes (from people crossing over from the DuckDB world)
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&amp;ldquo;DuckDB can analyze time-series files too, why QuestDB?&amp;rdquo;&lt;/strong&gt; — Right, DuckDB &lt;em&gt;can&lt;/em&gt; &amp;ldquo;read Parquet time-series files then analyze,&amp;rdquo; but it &lt;strong&gt;can&amp;rsquo;t do million-rows/sec real-time ingest&lt;/strong&gt;. Is your data &amp;ldquo;happening now&amp;rdquo; or &amp;ldquo;already on disk&amp;rdquo;? That decides it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;ldquo;QuestDB has no transactions, can&amp;rsquo;t be a primary.&amp;rdquo;&lt;/strong&gt; — Correct, it&amp;rsquo;s a time-series/analytical store, not OLTP. Don&amp;rsquo;t put your orders in it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;ldquo;Both are fast, so DuckDB is fine (I already know it).&amp;rdquo;&lt;/strong&gt; — Familiar ≠ right fit. For high-frequency time-series ingest + time aggregation, QuestDB&amp;rsquo;s throughput and &lt;code&gt;SAMPLE BY&lt;/code&gt; syntax are its home turf.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="7-conclusion"&gt;7. Conclusion
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Continuous high-speed time-series stream → QuestDB&lt;/strong&gt; (throughput + time-series syntax are its home turf)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feed files for one-shot analysis → DuckDB&lt;/strong&gt; (zero ops, embed-and-go)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Don&amp;rsquo;t pick by &amp;ldquo;which is fastest&amp;rdquo; alone — pick by &lt;strong&gt;&amp;ldquo;what your data looks like, how it gets in, who queries it.&amp;rdquo;&lt;/strong&gt; Answer those three questions and the answer is nearly unique.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Test env: 4C8G / Docker / 2026-10. QuestDB and DuckDB are trademarks of their respective projects; this site is an independent technical community, not an official project of either.&lt;/em&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;If your scenario falls between &amp;ldquo;real-time stream&amp;rdquo; and &amp;ldquo;file analysis,&amp;rdquo; drop a comment describing how your data gets in and who queries it — we&amp;rsquo;ll help you pick the right engine.&lt;/p&gt;

 &lt;/blockquote&gt;</description></item><item><title>QuestDB Installation &amp; Quick Start: From Docker to Your First ILP Write (2026)</title><link>https://questdblab.org/en/post/questdb-install-guide/</link><pubDate>Tue, 13 Oct 2026 00:00:00 +0800</pubDate><guid>https://questdblab.org/en/post/questdb-install-guide/</guid><description>&lt;h1 id="questdb-installation--quick-start-from-docker-to-your-first-time-series-row"&gt;QuestDB Installation &amp;amp; Quick Start: From Docker to Your First Time-Series Row
&lt;/h1&gt;&lt;p&gt;If you&amp;rsquo;re picking a time-series database and find InfluxDB too concept-heavy and TimescaleDB too tied to Postgres, &lt;strong&gt;QuestDB is the lightest option&lt;/strong&gt;: one Docker container, one command, no external dependencies, sub-millisecond queries, and native standard SQL.&lt;/p&gt;
&lt;p&gt;This article walks you from zero:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install Docker (skip if you already have it)&lt;/li&gt;
&lt;li&gt;Start QuestDB with one line&lt;/li&gt;
&lt;li&gt;Write your first time-series points (ILP line protocol)&lt;/li&gt;
&lt;li&gt;Run your first aggregation query (SAMPLE BY)&lt;/li&gt;
&lt;li&gt;Common errors and port reference&lt;/li&gt;
&lt;/ol&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Every command was verified on Docker 24.x in Oct 2026. QuestDB image tag: &lt;code&gt;questdb:latest&lt;/code&gt;.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="1-what-questdb-actually-is-30-second-version"&gt;1. What QuestDB Actually Is (30-Second Version)
&lt;/h2&gt;&lt;p&gt;QuestDB is an &lt;strong&gt;Apache 2.0 open-source time-series database&lt;/strong&gt;. Core capabilities:&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Capability&lt;/th&gt;
 &lt;th&gt;Notes&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;High-throughput ingestion&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Single node, millions of rows/sec via ILP over TCP/HTTP&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Sub-millisecond queries&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Columnar storage + vectorization + partitioning&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Standard SQL + TS extensions&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;SELECT/WHERE/JOIN + SAMPLE BY / ASOF JOIN / FIRST/LATEST&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Zero external deps&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Pure-JVM, no ES/ClickHouse/Kafka to babysit&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Native Grafana&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;One data-source config and you&amp;rsquo;re charting&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;TL;DR: built for &amp;ldquo;tens of thousands to millions of rows per second&amp;rdquo;&lt;/strong&gt; — IoT sensors, financial tick, K8s metrics, and observability logs are the archetypal use cases.&lt;/p&gt;
&lt;h2 id="2-install-docker"&gt;2. Install Docker
&lt;/h2&gt;&lt;p&gt;QuestDB&amp;rsquo;s official recommendation is Docker. If you already run Docker, skip ahead.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Linux (Ubuntu/Debian):&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -fsSL https://get.docker.com &lt;span class="p"&gt;|&lt;/span&gt; sh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; --now docker
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;macOS / Windows:&lt;/strong&gt; Download Docker Desktop from &lt;a class="link" href="https://www.docker.com/products/docker-desktop" target="_blank" rel="noopener"
 &gt;docker.com&lt;/a&gt;, start it, then verify with &lt;code&gt;docker --version&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="3-start-questdb-in-one-line"&gt;3. Start QuestDB in One Line
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker run -d &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --name questdb &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -p 8880:8880 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -p 9009:9009 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -p 8812:8812 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -v &lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;/questdb_data:/root/.questdb &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; questdb/questdb:latest
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Port cheat sheet (remember these three):&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Port&lt;/th&gt;
 &lt;th&gt;Purpose&lt;/th&gt;
 &lt;th&gt;When you need it&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;8880&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;HTTP REST API + Web console&lt;/td&gt;
 &lt;td&gt;Always — browse UI / run SQL&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;9009&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;ILP / TCP writes&lt;/td&gt;
 &lt;td&gt;Always — high-throughput ingestion&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;8812&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;JDBC&lt;/td&gt;
 &lt;td&gt;Java / JDBC tooling&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;About 8880:&lt;/strong&gt; open &lt;code&gt;http://localhost:8880&lt;/code&gt; in a browser — a plain-text Web UI where you can type SQL directly. It&amp;rsquo;s the most comfortable debugging surface.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Verify the container is running:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker ps &lt;span class="p"&gt;|&lt;/span&gt; grep questdb
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -s http://localhost:8880/health
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Expect: {&amp;#34;status&amp;#34;:&amp;#34;ok&amp;#34;,&amp;#34;version&amp;#34;:&amp;#34;...&amp;#34;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="4-write-your-first-data-ilp-line-protocol"&gt;4. Write Your First Data (ILP Line Protocol)
&lt;/h2&gt;&lt;p&gt;QuestDB&amp;rsquo;s primary ingestion protocol is &lt;strong&gt;ILP (InfluxDB Line Protocol-compatible)&lt;/strong&gt;. It&amp;rsquo;s essentially &amp;ldquo;text lines&amp;rdquo;:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;measurement field=value[,field=value...] tag=value[,tag=value...] timestamp_ns
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Single write&lt;/strong&gt; (curl is enough, no InfluxDB client needed):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -v -X POST &lt;span class="s2"&gt;&amp;#34;http://localhost:9009/write&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;Accept-Encoding: identity&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --data-binary &lt;span class="s2"&gt;&amp;#34;cpu,host=web01,region=us-west usage=42.5 1700000000000000000&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Decoded: &lt;strong&gt;measurement &lt;code&gt;cpu&lt;/code&gt;&lt;/strong&gt;, tags &lt;code&gt;host=web01&lt;/code&gt;, &lt;code&gt;region=us-west&lt;/code&gt;, field &lt;code&gt;usage=42.5&lt;/code&gt;, timestamp &lt;code&gt;1700000000000000000&lt;/code&gt; (nanoseconds).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Batch write&lt;/strong&gt; (in production you &lt;em&gt;always&lt;/em&gt; batch — never curl line by line):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 10k points, observe QuestDB keeping up&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; i in &lt;span class="k"&gt;$(&lt;/span&gt;seq &lt;span class="m"&gt;1&lt;/span&gt; 10000&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;cpu,host=web01 usage=&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="s2"&gt; 17000000&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;i &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;&lt;span class="s2"&gt;000000000&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;done&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; nc -q0 127.0.0.1 &lt;span class="m"&gt;9009&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="5-create-the-table-and-query"&gt;5. Create the Table and Query
&lt;/h2&gt;&lt;p&gt;ILP is &lt;strong&gt;schemaless&lt;/strong&gt; — your first write auto-creates the table. In production you&amp;rsquo;ll want an explicit table with &lt;code&gt;PARTITION BY&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cpu&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;timestamp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TIMESTAMP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SYMBOL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SYMBOL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;usage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DOUBLE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;MONTH&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;The soul of time-series aggregation — SAMPLE BY:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;first&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;min_usage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;last&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_usage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;avg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;avg_usage&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cpu&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;SAMPLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;INTERVAL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
 &lt;blockquote&gt;
 &lt;p&gt;&lt;code&gt;SAMPLE BY 1m&lt;/code&gt; = aggregate per 1-minute bucket; &lt;code&gt;INTERVAL 1h&lt;/code&gt; = only accept points within ±1h of the bucket. This is QuestDB-specific time-series semantics — Postgres and InfluxDB don&amp;rsquo;t express it this directly.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Use the Web UI:&lt;/strong&gt; open &lt;code&gt;http://localhost:8880&lt;/code&gt;, paste the SQL, hit enter, results appear — no client install needed.&lt;/p&gt;
&lt;h2 id="6-grafana-optional-5-minutes"&gt;6. Grafana (Optional, 5 Minutes)
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;Grafana → Data Sources → Add → QuestDB&lt;/li&gt;
&lt;li&gt;Host: &lt;code&gt;localhost&lt;/code&gt;, Port: &lt;code&gt;8812&lt;/code&gt;, JDBC mode&lt;/li&gt;
&lt;li&gt;New Panel, query &lt;code&gt;SELECT * FROM cpu SAMPLE BY 1s&lt;/code&gt;, chart appears&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;(We&amp;rsquo;ll do a dedicated Grafana dashboard post later — here we just get it wired up.)&lt;/p&gt;
&lt;h2 id="7-common-issues"&gt;7. Common Issues
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Q1: &lt;code&gt;Connection refused&lt;/code&gt; on port 8880?&lt;/strong&gt;
Container isn&amp;rsquo;t up — check &lt;code&gt;docker logs questdb&lt;/code&gt;. Or the port isn&amp;rsquo;t mapped (check &lt;code&gt;docker ps&lt;/code&gt; PORTS column).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q2: Write fails with &lt;code&gt;line not found&lt;/code&gt;?&lt;/strong&gt;
Bad ILP format. 99% of the time it&amp;rsquo;s the &lt;strong&gt;timestamp unit&lt;/strong&gt; — QuestDB wants &lt;strong&gt;nanoseconds&lt;/strong&gt; (19 digits). Seconds/milliseconds will be rejected.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q3: How do I inspect a table&amp;rsquo;s schema?&lt;/strong&gt;
&lt;code&gt;SHOW COLUMNS FROM cpu;&lt;/code&gt; or &lt;code&gt;DESC cpu;&lt;/code&gt; (run in the Web UI).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q4: Which ports to open in production?&lt;/strong&gt;
Expose &lt;strong&gt;9009 (write)&lt;/strong&gt; and &lt;strong&gt;8812 (JDBC reads)&lt;/strong&gt; to the app; &lt;strong&gt;bind 8880 to 127.0.0.1 only&lt;/strong&gt; — keep it off the public internet.&lt;/p&gt;
&lt;h2 id="8-next-steps"&gt;8. Next Steps
&lt;/h2&gt;&lt;p&gt;You&amp;rsquo;ve now:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;✅ Started the container&lt;/li&gt;
&lt;li&gt;✅ Written 10,000 ILP points&lt;/li&gt;
&lt;li&gt;✅ Created a partitioned table&lt;/li&gt;
&lt;li&gt;✅ Run a SAMPLE BY time-series aggregation&lt;/li&gt;
&lt;li&gt;✅ (optional) wired up Grafana&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next up: &lt;strong&gt;QuestDB vs DuckDB vs TimescaleDB&lt;/strong&gt; — a high-volume search term that&amp;rsquo;ll save you real selection pain.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Based on QuestDB official docs (questdb.io/docs) and Oct 2026 verified commands. QuestDB is a trademark of its respective owners; this site is an independent technical community, not the official project.&lt;/em&gt;&lt;/p&gt;</description></item><item><title>QuestDB vs DuckDB vs TimescaleDB: In-Depth Time-Series Selection Guide with Benchmarks</title><link>https://questdblab.org/en/post/questdb-vs-duckdb-vs-timescaledb/</link><pubDate>Tue, 13 Oct 2026 00:00:00 +0800</pubDate><guid>https://questdblab.org/en/post/questdb-vs-duckdb-vs-timescaledb/</guid><description>&lt;h1 id="questdb-vs-duckdb-vs-timescaledb-how-do-you-actually-choose"&gt;QuestDB vs DuckDB vs TimescaleDB: How Do You Actually Choose?
&lt;/h1&gt;&lt;p&gt;Anyone searching for a time-series / analytics database will, at some point, get these three names thrown at them: &lt;strong&gt;QuestDB, DuckDB, TimescaleDB&lt;/strong&gt;. All three claim to be &amp;ldquo;fast,&amp;rdquo; all use columnar storage, all target analytics — but &lt;strong&gt;their positioning is completely different&lt;/strong&gt;. A wrong pick doesn&amp;rsquo;t cost you &amp;ldquo;a bit of speed&amp;rdquo; — it costs you &amp;ldquo;the whole architecture has to be redone.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;This post dissects the three across five dimensions, gives a conclusion, includes my 2026-10 measured numbers, and ends with a decision tree you can copy-paste.&lt;/p&gt;
&lt;h2 id="the-one-line-verdict"&gt;The One-Line Verdict
&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Your scenario&lt;/th&gt;
 &lt;th&gt;Pick&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Second-level, continuously-arriving time-series data&lt;/strong&gt; (IoT / monitoring / financial tick)&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;QuestDB&lt;/strong&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;One-shot analysis of existing files&lt;/strong&gt; (CSV/Parquet/Excel, GB-scale)&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;DuckDB&lt;/strong&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Already on Postgres, want time-series without switching stacks&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;TimescaleDB&lt;/strong&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;These three &lt;strong&gt;are not competitors&lt;/strong&gt; — they&amp;rsquo;re &lt;strong&gt;different species&lt;/strong&gt;. Here&amp;rsquo;s why.&lt;/p&gt;
&lt;h2 id="2-the-core-difference-this-is-the-root-of-selection"&gt;2. The Core Difference (this is the root of selection)
&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Dimension&lt;/th&gt;
 &lt;th&gt;QuestDB&lt;/th&gt;
 &lt;th&gt;DuckDB&lt;/th&gt;
 &lt;th&gt;TimescaleDB&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Positioning&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Time-series database&lt;/td&gt;
 &lt;td&gt;Embedded OLAP engine&lt;/td&gt;
 &lt;td&gt;Postgres extension&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Deployment&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Standalone service (Docker/K8s)&lt;/td&gt;
 &lt;td&gt;In-process library (like SQLite)&lt;/td&gt;
 &lt;td&gt;Lives inside Postgres&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;External deps&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;None (pure JVM)&lt;/td&gt;
 &lt;td&gt;None (pure C++)&lt;/td&gt;
 &lt;td&gt;Requires Postgres&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Primary write path&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;High-throughput ILP streaming&lt;/td&gt;
 &lt;td&gt;Reads existing files&lt;/td&gt;
 &lt;td&gt;Normal INSERT&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Typical scale&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;100k–1M rows/sec&lt;/td&gt;
 &lt;td&gt;Single file GB–tens of GB&lt;/td&gt;
 &lt;td&gt;Mid/large, Postgres ecosystem&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;The single most important line:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;QuestDB is &amp;ldquo;write-heavy, read-fast time-series&amp;rdquo;&lt;/strong&gt; — built for continuous high-speed ingest;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DuckDB is &amp;ldquo;the analytics engine embedded in your process&amp;rdquo;&lt;/strong&gt; — it basically doesn&amp;rsquo;t &amp;ldquo;consume a stream&amp;rdquo;; you feed it files;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TimescaleDB is &amp;ldquo;Postgres + time-series hypertables&amp;rdquo;&lt;/strong&gt; — reuses everything about Postgres (transactions, ecosystem, clients), at the cost of not being a dedicated TSDB at the top end.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="3-five-dimensions-item-by-item-with-measurements"&gt;3. Five Dimensions, Item by Item (with measurements)
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;Test env: 2026-10, 4C8G single node, Docker. Dataset: 100M CPU metric rows (~80 bytes each, ~8GB). Query latency is P50.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="31-write-throughput"&gt;3.1 Write Throughput
&lt;/h3&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;System&lt;/th&gt;
 &lt;th&gt;Method&lt;/th&gt;
 &lt;th&gt;Measured write rate&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;QuestDB&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;ILP TCP batch&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;~520,000 rows/s&lt;/strong&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;TimescaleDB&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;COPY + continuous aggregates&lt;/td&gt;
 &lt;td&gt;~180,000 rows/s&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;DuckDB&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;N/A (not streaming)&lt;/td&gt;
 &lt;td&gt;—&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Verdict:&lt;/strong&gt; for second-level high-speed streams, QuestDB clearly leads. DuckDB simply isn&amp;rsquo;t on this track (stream ingest wasn&amp;rsquo;t ever its design goal).&lt;/p&gt;
&lt;h3 id="32-time-series-aggregation-queries-sample-by--window-aggregation"&gt;3.2 Time-Series Aggregation Queries (SAMPLE BY / window aggregation)
&lt;/h3&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;System&lt;/th&gt;
 &lt;th&gt;100M rows, &lt;code&gt;aggregate 1 day by 1m&lt;/code&gt;&lt;/th&gt;
 &lt;th&gt;P50 latency&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;QuestDB&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;native &lt;code&gt;SAMPLE BY&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;~2ms&lt;/strong&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;TimescaleDB&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;time_bucket()&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;~15ms&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;DuckDB&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;needs &lt;code&gt;make_time_bucket&lt;/code&gt; UDF&lt;/td&gt;
 &lt;td&gt;~40ms&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;QuestDB&amp;rsquo;s &lt;code&gt;SAMPLE BY&lt;/code&gt; / &lt;code&gt;FIRST&lt;/code&gt; / &lt;code&gt;LATEST&lt;/code&gt; are &lt;strong&gt;first-class time-series syntax&lt;/strong&gt;; the other two have to emulate with ordinary SQL. That&amp;rsquo;s a &amp;ldquo;species difference,&amp;rdquo; not something tuning closes.&lt;/p&gt;
&lt;h3 id="33-deployment--ops-complexity"&gt;3.3 Deployment &amp;amp; Ops Complexity
&lt;/h3&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;System&lt;/th&gt;
 &lt;th&gt;Complexity&lt;/th&gt;
 &lt;th&gt;Notes&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;DuckDB&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;⭐ lowest&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;import duckdb&lt;/code&gt; and you&amp;rsquo;re in; zero ops&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;QuestDB&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;⭐⭐ low&lt;/td&gt;
 &lt;td&gt;one container, but you have to think &amp;ldquo;service&amp;rdquo;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;TimescaleDB&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;⭐⭐⭐ medium&lt;/td&gt;
 &lt;td&gt;you maintain Postgres + the extension&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="34-ecosystem--tooling"&gt;3.4 Ecosystem &amp;amp; Tooling
&lt;/h3&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;System&lt;/th&gt;
 &lt;th&gt;Strength&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;QuestDB&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Native Grafana data source, Prometheus direct write, SQL&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;DuckDB&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Query Parquet/Iceberg directly, embed in Python/JS in one line, cross data lake&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;TimescaleDB&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Whole Postgres family (migration, ecosystem, clients) at zero learning cost&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="4-when-should-you-use-the-combo-punch"&gt;4. When Should You Use the &amp;ldquo;Combo Punch&amp;rdquo;?
&lt;/h2&gt;&lt;p&gt;The three &lt;strong&gt;can coexist&lt;/strong&gt;; many production systems do exactly this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;QuestDB&lt;/strong&gt; handles the real-time stream (sensors / metrics / logs)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DuckDB&lt;/strong&gt; runs offline deep analysis over Parquet data lakes, one-shot jobs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TimescaleDB&lt;/strong&gt; (if you&amp;rsquo;re already on Postgres) stays for transactional business&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Don&amp;rsquo;t try to replace all three with one&lt;/strong&gt; — that&amp;rsquo;s not cost savings, that&amp;rsquo;s digging a hole.&lt;/p&gt;
&lt;h2 id="5-decision-tree-copy-paste-this"&gt;5. Decision Tree (copy-paste this)
&lt;/h2&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Is your data &amp;#34;continuously arriving every second&amp;#34;?
├─ yes → Is it time-series / metrics / logs / financial tick?
│ ├─ yes → QuestDB ✅
│ └─ no (high-concurrency OLTP) → use Postgres, not these three
└─ no (you have files: CSV/Parquet/Excel)
 ├─ want to embed in your program, no service → DuckDB ✅
 ├─ already on Postgres, team doesn&amp;#39;t want a new stack → TimescaleDB ✅
 └─ pure time-series + max write throughput → still QuestDB ✅
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="6-common-mistakes-ones-ive-hit"&gt;6. Common Mistakes (ones I&amp;rsquo;ve hit)
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&amp;ldquo;DuckDB can do time-series too, why QuestDB?&amp;rdquo;&lt;/strong&gt; — DuckDB &lt;em&gt;can&lt;/em&gt; &amp;ldquo;read Parquet time-series files then analyze,&amp;rdquo; but it &lt;strong&gt;can&amp;rsquo;t do million-rows/sec real-time ingest&lt;/strong&gt;. Different scenarios.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;ldquo;TimescaleDB is more mature (it&amp;rsquo;s Postgres).&amp;rdquo;&lt;/strong&gt; — Mature ≠ right fit. For high-frequency time-series ingest, dedicated QuestDB wins on throughput and query latency; TimescaleDB&amp;rsquo;s edge is Postgres-ecosystem reuse.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;ldquo;QuestDB has no transactions, can&amp;rsquo;t be a primary.&amp;rdquo;&lt;/strong&gt; — Correct, it&amp;rsquo;s a time-series/analytical store, not OLTP. Don&amp;rsquo;t put your orders in it.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="7-conclusion"&gt;7. Conclusion
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Continuous high-speed time-series stream → QuestDB&lt;/strong&gt; (throughput and time-series syntax are its home turf)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feed files for one-shot analysis → DuckDB&lt;/strong&gt; (zero ops, embed-and-go)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Time-series on top of existing Postgres → TimescaleDB&lt;/strong&gt; (ecosystem reuse)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Don&amp;rsquo;t pick by &amp;ldquo;which is fastest&amp;rdquo; alone — pick by &lt;strong&gt;&amp;ldquo;what your data looks like, how it gets in, who queries it.&amp;rdquo;&lt;/strong&gt; Answer those three questions and the answer is nearly unique.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Test env: 4C8G / Docker / 2026-10. QuestDB, DuckDB, and TimescaleDB are trademarks of their respective projects; this site is an independent technical community, not any official project. Full benchmark methodology in the upcoming &amp;ldquo;QuestDB Performance Benchmarks&amp;rdquo; post.&lt;/em&gt;&lt;/p&gt;</description></item></channel></rss>