<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nicolas Hourcard</title>
    <description>The latest articles on DEV Community by Nicolas Hourcard (@nicquestdb).</description>
    <link>https://dev.to/nicquestdb</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F284061%2F8910b1f6-099c-40a0-a6e0-df64258c5002.jpg</url>
      <title>DEV Community: Nicolas Hourcard</title>
      <link>https://dev.to/nicquestdb</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nicquestdb"/>
    <language>en</language>
    <item>
      <title>QuestDB 6.6 - Dynamic Commits</title>
      <dc:creator>Nicolas Hourcard</dc:creator>
      <pubDate>Mon, 28 Nov 2022 14:07:58 +0000</pubDate>
      <link>https://dev.to/nicquestdb/questdb-66-dynamic-commits-1ch8</link>
      <guid>https://dev.to/nicquestdb/questdb-66-dynamic-commits-1ch8</guid>
      <description>&lt;p&gt;We are excited to announce the release of &lt;a href="https://questdb.io/blog/2022/11/25/questdb-6.6.1-dynamic-commits"&gt;QuestDB 6.6.1&lt;/a&gt;, which brings dynamic commits to optimize ingestion throughput and data freshness for reads. In this blog post, our CTO, Vlad, shares the story driving the creation of the dynamic commits.&lt;/p&gt;

&lt;h2&gt;
  
  
  QuestDB's data structure and out-of-order data ingestion
&lt;/h2&gt;

&lt;p&gt;Many storage systems adopt a Log-Structured Merge tree at their core. QuestDB differs from them, and the ingested data will always be ordered by timestamp once it is committed to disk. &lt;a href="https://questdb.io/blog/2021/05/10/questdb-release-6-0-tsbs-benchmark/"&gt;QuestDB 6.0&lt;/a&gt; enabled out-of-order ingestion, for which we introduced a commit lag to optimize ingestion throughput for unordered data. The commit lag includes a time-based buffer and delays the data commit. This way, out-of-order data can be re-ordered on the fly in memory. QuestDB's in-memory reordering is particularly efficient, and avoids heavy copy-on-merge operations, which would be needed otherwise.&lt;/p&gt;

&lt;p&gt;As such, we have an implicit trade-off between the ingestion throughput of unordered data and the availability of data for reads. A higher buffer implies a longer time delay for the data to be available for reads, while a short buffer might affect disk write throughput, as we need to reshuffle already committed out-of-order data.&lt;/p&gt;

&lt;p&gt;To recap, when treating the incoming data, the commit lag ensures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data is sorted chronologically.&lt;/li&gt;
&lt;li&gt;New data is merged with the existing one.&lt;/li&gt;
&lt;li&gt;A consistent view of the existing data is maintained for concurrent reads.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AVp1HMh9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mbgqms5d3ouk22fpw9e4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AVp1HMh9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mbgqms5d3ouk22fpw9e4.png" alt="QuestDB dynamic commit, re-ordering out-of-order data in memory" width="880" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For QuestDB 6.5.5 and earlier versions, users needed to understand the "shape" of their data to adjust the commit lag value, either through server configuration or query settings.&lt;/p&gt;

&lt;p&gt;A misconfigured commit lag would lead to user pain and frustration: some of our users would expect data to be available for reads immediately, but the default configuration was out of whack. For heavy out-of-order ingestion patterns, the default commit lag would lead to too many copy-on-merge operations and significantly slow down the database. And this was where the story started.&lt;/p&gt;

&lt;h1&gt;
  
  
  Community-driven development
&lt;/h1&gt;

&lt;p&gt;A couple of weeks ago, I was working on a massive WAL (Write Ahead Log) PR, when Nic, our CEO, sent me a thread of messages:&lt;/p&gt;

&lt;p&gt;Nic: FYI I asked Javier and Imre to connect and look at this commit lag together. Our default settings are not good enough…Someone in the community just asked me if the best we can do is ingestion with a 5-minute delay. These default settings give the wrong impression that we cannot process data in real time. Let's brainstorm.&lt;/p&gt;

&lt;p&gt;Me: They can reduce the commit lag, why would not they do that? They can set it to 0?&lt;/p&gt;

&lt;p&gt;Nic: They don't know that the commit lag is configurable, and this leaves a bad impression on new users.&lt;/p&gt;

&lt;p&gt;This feedback was too important to ignore, so I caught up with our Core Engineer, Imre Aranyosi, and DevRel, Javier Ramirez. It turned out that Javier had produced a demo project in Go, sending data to QuestDB Cloud in small batches - approximately 10k rows every 50 ms. When querying data from this project, Javier could not see new data immediately. Similarly, data visibility is one of the most frequently asked questions on QuestDB Slack as well as on Stackoverflow. To our users, it wasn't clear which configuration parameters to set and where to show this data, either. We had to investigate this problem further.&lt;/p&gt;

&lt;p&gt;Imre and I began exploring and we soon realized that it was due to the commit lag setting that data were not readily available. To increase data freshness, we had to commit more often and decouple the commit frequency from the commit lag value. We wanted to improve our user experience, without complicating the database configuration. So we went back to the whiteboard and considered the commit lag anew. Its optimal size depended on the shape of the incoming data, which was not static. This meant that the commit lag size had to be dynamic! We needed to predict the commit lag size and resize the value dynamically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dynamic commits
&lt;/h2&gt;

&lt;p&gt;This is what we eventually implemented for QuestDB 6.6.1: to predict the correct commit lag value, QuestDB takes the maximum of the latest 4 overlap values with a multiplication factor - a bigger commit lag is better than a smaller one. This prediction is updated every second. The commit lag value shrinks down to 0 when data stops overlapping (no out-of-order data) and inflates rapidly in response to out-of-order demands, depending on the data shape prediction.&lt;/p&gt;

&lt;p&gt;Javier has upgraded his demo project to QuestDB 6.6.1 and now data is visible instantly. Our DevRel is happy, and so are our users: it does not matter the data ingestion method and the scope of the data, QuestDB automatically adjusts settings and delivers the optimal data immediacy.&lt;/p&gt;

&lt;p&gt;In short, users do not need to do anything to benefit from the optimal ingestion rate and data availability for read operations. Check us out on &lt;a href="https://github.com/questdb/questdb"&gt;GitHub&lt;/a&gt; for more details.&lt;/p&gt;

</description>
      <category>database</category>
      <category>opensource</category>
      <category>java</category>
      <category>analytics</category>
    </item>
    <item>
      <title>How we achieved write speeds of 1.4 million rows per second</title>
      <dc:creator>Nicolas Hourcard</dc:creator>
      <pubDate>Fri, 21 May 2021 12:59:05 +0000</pubDate>
      <link>https://dev.to/questdb/how-we-achieved-write-speeds-of-1-4-million-rows-per-second-1a9l</link>
      <guid>https://dev.to/questdb/how-we-achieved-write-speeds-of-1-4-million-rows-per-second-1a9l</guid>
      <description>&lt;p&gt;At QuestDB, we've built an open-source time series database focused on performance. We started QuestDB so that we could bring our experience in low-latency trading and the technical approaches we developed in this domain to a variety of real-time data processing use cases.&lt;/p&gt;

&lt;p&gt;The journey to today's version of QuestDB began with the original prototype in 2013, and we've described what happened since in a post published &lt;a href="https://news.ycombinator.com/item?id=23975807" rel="noopener noreferrer"&gt;during our HackerNews launch&lt;/a&gt; last year. Our users deploy QuestDB to make time series analysis fast, efficient, and convenient in financial services, IoT, application monitoring, and machine learning.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's the best way to store time series data?
&lt;/h2&gt;

&lt;p&gt;In the early stages of the project, we were inspired by vector-based append-only systems like kdb+ because of the advantages of speed and the simple code path this model brings. QuestDB’s data model uses what we call &lt;em&gt;time-based arrays&lt;/em&gt; which is a linear data structure. This allows QuestDB to slice data during ingestion in small chunks and process it all in parallel. Data that arrives in the wrong time order is dealt with and reordered in memory before being persisted to disk. Therefore, data lands on the database ordered by time already. As such, QuestDB does not rely on computationally intense indices to reorder data for any given time-series queries.&lt;/p&gt;

&lt;p&gt;This liner model differs from the LSM trees or B-tree-based storage engines found in other open source databases such as InfluxDB or TimescaleDB.&lt;/p&gt;

&lt;p&gt;Beyond ingestion capabilities, QuestDB’s data layout enables CPUs to access data faster. Our codebase leverages modern CPU architecture with SIMD instructions to request that the same operation be performed on multiple data elements in parallel. We store data in columns and partition it by time to lift the minimal amount of data from the disk for a given query.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwg2aqieemlkz5r5d2dym.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwg2aqieemlkz5r5d2dym.png" alt="A diagram showing the column-based storage model of QuestDB which allows for parallelizing work in tables"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How does QuestDB compare to ClickHouse, InfluxDB and TimescaleDB
&lt;/h2&gt;

&lt;p&gt;We saw the &lt;a href="https://github.com/timescale/tsbs" rel="noopener noreferrer"&gt;Time Series Benchmark Suite&lt;/a&gt; (TSBS) regularly coming up in discussions about database performance and decided we should provide the ability to benchmark QuestDB along with other systems. The TSBS is a collection of Go programs to generate datasets and then benchmark read and write performance. The suite is extensible so that different use cases and query types can be included and compared across systems.&lt;/p&gt;

&lt;p&gt;Here are our results of the benchmark with the &lt;code&gt;cpu-only&lt;/code&gt; use case using up to fourteen workers on an AWS EC2 &lt;code&gt;m5.8xlarge&lt;/code&gt; instance with sixteen cores.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb27s5sk6dijrfamln2da.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb27s5sk6dijrfamln2da.png" alt="A chart comparing the maximum throughput of four database systems, showing QuestDB hitting ingestion limits with less resources than other systems"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We reach maximum ingestion performance using four workers, whereas the other systems require more CPU resources to hit maximum throughput. QuestDB achieves 959k rows/sec with 4 threads. We find that InfluxDB needs 14 threads to reach its max ingestion rate (334k rows/sec), while TimescaleDB reaches 145k rows/sec with 4 threads. ClickHouse hits 914k rows/sec with twice as many threads as QuestDB.&lt;/p&gt;

&lt;p&gt;When running on 4 threads, QuestDB is 1.7x faster than ClickHouse, 6.5x faster than InfluxDB and 6.6x faster than TimescaleDB.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F82rkh366kuio6tqp1e7t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F82rkh366kuio6tqp1e7t.png" alt="Time series benchmark suite results showing QuestDB outperforming ClickHouse, TimescaleDB and InfluxDB when using four workers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When we run the suite again using an AMD Ryzen5 processor, we found that we were able to hit maximum throughput of 1.43 million rows per second using 5 threads. This is compared to the &lt;a href="https://aws.amazon.com/ec2/instance-types/" rel="noopener noreferrer"&gt;Intel Xeon Platinum&lt;/a&gt; that's in use by our reference benchmark &lt;code&gt;m5.8xlarge&lt;/code&gt; instance on AWS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frf44e9irxw67aty77jwk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frf44e9irxw67aty77jwk.png" alt="A chart comparing the maximum throughput of QuestDB when utilizing an Intel Xeon Platinum processor versus an AMD Ryzen5 processor."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How should you store out-of-order time series data?
&lt;/h2&gt;

&lt;p&gt;Re-ordering data which is "out-of-order" (O3) during ingestion proved particularly challenging. It is a new approach that we wanted to detail a little bit more in this article. Our idea of how we could handle out out-of-order ingestion was to add a three-stage approach:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Keep the append model until records arrive out-of-order &lt;/li&gt;
&lt;li&gt;Sort uncommitted records in a staging area in-memory&lt;/li&gt;
&lt;li&gt;Reconcile and merge the sorted out-of-order data and persisted data at commit time&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first two steps are straightforward and easy to implement, and handling append-only data is unchanged. The heavy out-of-order commit kicks in only when there is data in the staging area. The bonus of this design is that the output is vectors, meaning our vector-based readers are still compatible.&lt;/p&gt;

&lt;p&gt;This pre-commit sort-and-merge adds an extra processing phase to ingestion with an accompanying performance penalty. We nevertheless decided to explore this approach and see how far we could reduce the penalty by optimizing the out-of-order commit.&lt;/p&gt;

&lt;h2&gt;
  
  
  How we sort, merge and commit out-of-order time series data
&lt;/h2&gt;

&lt;p&gt;Processing a staging area gives us a unique opportunity to analyze the data holistically where we can avoid physical &lt;em&gt;merges&lt;/em&gt; altogether and get away with fast and straightforward &lt;code&gt;memcpy&lt;/code&gt; or similar data movement methods. Such methods can be parallelized thanks to our column-based storage. We can employ SIMD and non-temporal data access where it makes a difference.&lt;/p&gt;

&lt;p&gt;We sort the timestamp column from the staging area via an optimized version of radix sort, and the resulting index is used to reshuffle the remaining columns in the staging area in parallel:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkg2xjtcc5c7nek6c9b4h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkg2xjtcc5c7nek6c9b4h.png" alt="A diagram illustrating how sorting is applied to unordered database records based on a timestamp column order"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The now-sorted staging area is mapped relative to the existing partition data. It may not be obvious from the start but we are trying to establish the type of operation needed and the dimensions of each of the three groups below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4zeinflbfvd9z2mxih42.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4zeinflbfvd9z2mxih42.png" alt="A diagram illustrating the combinations of merge operations that can be applied to two data sets"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When merging datasets in this way, the prefix and suffix groups can be persisted data, out-of-order data, or none. The merge group is where more cases occur as it can be occupied by persisted data, out-of-order data, both out-of-order and persisted data, or none.&lt;/p&gt;

&lt;p&gt;When it's clear how to group and treat data in the staging area, a pool of workers perform the required operations, calling &lt;code&gt;memcpy&lt;/code&gt; in trivial cases and shifting to SIMD-optimized code for everything else. With a prefix, merge, and suffix split, the maximum &lt;code&gt;liveliness&lt;/code&gt; of the commit (how susceptible it is to add more CPU capacity) is &lt;code&gt;partitions_affected&lt;/code&gt; x &lt;code&gt;number_of_columns&lt;/code&gt; x &lt;code&gt;3&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How often should time series data be sorted and merged?
&lt;/h2&gt;

&lt;p&gt;Being able to copy data fast is a good option, but we think that heavy data copying can be avoided in most time series ingestion scenarios. Assuming that most real-time out-of-order situations are caused by the delivery mechanism and hardware jitter, we can deduce that the timestamp distribution will be contained by some boundary.&lt;/p&gt;

&lt;p&gt;For example, if any new timestamp value has a high probability to fall within 10 seconds of the previously received value, the boundary is then 10 seconds, and we call this boundary &lt;em&gt;lag.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When timestamp values follow this pattern, deferring the commit can render out-of-order commits a normal append operation. The out-of-order system can deal with any variety of lateness, but if incoming data is late within the time specified by &lt;em&gt;lag&lt;/em&gt;, it will be prioritized for faster processing.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to compare time series database performance
&lt;/h2&gt;

&lt;p&gt;We have opened a pull request (&lt;a href="https://github.com/timescale/tsbs/issues/157" rel="noopener noreferrer"&gt;Questdb benchmark support&lt;/a&gt;) in TimescaleDB's TSBS GitHub repository, to add the ability to run the benchmark against QuestDB. In the meantime, users may clone &lt;a href="https://github.com/questdb/tsbs" rel="noopener noreferrer"&gt;our fork of the benchmark&lt;/a&gt; and run the suite to see the results for themselves.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tsbs_generate_data &lt;span class="nt"&gt;--use-case&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"cpu-only"&lt;/span&gt; &lt;span class="nt"&gt;--seed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;123 &lt;span class="nt"&gt;--scale&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4000 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--timestamp-start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"2016-01-01T00:00:00Z"&lt;/span&gt; &lt;span class="nt"&gt;--timestamp-end&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"2016-01-02T00:00:00Z"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--log-interval&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"10s"&lt;/span&gt; &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"influx"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/bigcpu

tsbs_load_questdb &lt;span class="nt"&gt;--file&lt;/span&gt; /tmp/bigcpu &lt;span class="nt"&gt;--workers&lt;/span&gt; 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Building an open source database with a permissive license
&lt;/h2&gt;

&lt;p&gt;Pushing database performance further while making it easy for developers to get started with our product motivates us every day. This is why we are focused on building a solid community of developers who can participate and improve the product through our open source distribution model.&lt;/p&gt;

&lt;p&gt;Beyond making QuestDB easy to use, we want to make it easy to audit, review, and make code or general project contributions. All of QuestDB's source code is available on &lt;a href="https://github.com/questdb/questdb" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; under the Apache 2.0 license and we welcome all sorts of contributions from GitHub issues to pull requests.&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>opensource</category>
      <category>database</category>
      <category>performance</category>
    </item>
    <item>
      <title>What is time-series data, and why are we building a time-series database (TSDB)?</title>
      <dc:creator>Nicolas Hourcard</dc:creator>
      <pubDate>Thu, 19 Nov 2020 18:02:51 +0000</pubDate>
      <link>https://dev.to/questdb/what-is-time-series-data-and-why-are-we-building-a-time-series-database-tsdb-47b9</link>
      <guid>https://dev.to/questdb/what-is-time-series-data-and-why-are-we-building-a-time-series-database-tsdb-47b9</guid>
      <description>&lt;p&gt;This blog post covers the basics of time-series data and why time-series databases have seen such an explosion in popularity since the category emerged a decade ago. Additionally, we will briefly cover the origin story of QuestDB, why we set out to build a new database from scratch and go through the database design choices and trade-offs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Time-series data and characteristics of TSDBs
&lt;/h2&gt;

&lt;p&gt;Time-series data is everywhere. Sensors, financial exchanges, servers, and software applications generate streams of events, which need to be analyzed on the fly. Time-series databases (TSDB) emerged as a category to better deal with vasts amount of machine data. These specialized Database Management Systems (DMBS) are now empowering millions of developers to collect, store, process, and analyze data over time. With new time-series forecasting methods and machine learning models, companies are now better equipped to train and refine their models to predict future outcomes more accurately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Time-Series data explained
&lt;/h3&gt;

&lt;p&gt;Time series is a succession of data points ordered by time. Time-series data is often plotted on a chart where the x-axis is time and the y-axis is a metric that changes over time. For example, stock prices change every microsecond or even nanosecond, and the trend is best presented as time-series data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--U_gblhsL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ekrtnvdgz11h5j2kwc6b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--U_gblhsL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ekrtnvdgz11h5j2kwc6b.png" alt="Apple share price over the last five years: time series data" width="880" height="505"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Time-series data has always been plentiful in financial services with fast-changing tick price data and in e-commerce/ad-tech to better understand user analytics. With the rise in connected devices, application monitoring, and observability, time-series data is now critical in nearly all fields. We list a couple of examples below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--e4DGk0nj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vzng2axb76vycu8w18so.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--e4DGk0nj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vzng2axb76vycu8w18so.png" alt="The primary use cases for time-series databases such as QuestDB" width="880" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Time-series data has several unique characteristics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The amount of data created and processed is large.&lt;/li&gt;
&lt;li&gt;The amount of data flowing from the source is often uninterrupted.&lt;/li&gt;
&lt;li&gt;The volume is also unpredictable and can come with bursts of high volumes of data incoming at irregular intervals. This is very common in financial markets, with spikes of trading volume occurring after events, which are difficult to predict.&lt;/li&gt;
&lt;li&gt;Fresh data needs to be analyzed on the fly. Anomaly detection is a good example.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With the rise of time-series data, time series has been the fastest-growing database category for the past five years according to DB-engines.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--y4x21qf---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/79a910bflbjwk4yj7cm0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--y4x21qf---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/79a910bflbjwk4yj7cm0.png" alt="Popularity by database category since 2018" width="880" height="472"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Time-series databases design
&lt;/h3&gt;

&lt;p&gt;As use cases and the need for time series analysis are increasing exponentially, so is the amount of raw data itself. To better cope with the ever-growing amount of data, time-series databases emerged a decade ago. They focus on performance with fast ingests to process a higher number of data points. The trade-off is less stringent consistency guarantees, which are typically must-haves for OLTP workloads. It is pretty common for time-series databases not to be ACID compliant. &lt;/p&gt;

&lt;p&gt;Unlike traditional databases in which older data entries are typically updated with the most recent data point to show the latest state, time-series databases continuously accumulate data points over time. This way, one can draw insights from the evolution of metrics to conclude meaningful insights from the data. This is why TSDBs are optimized for write operations rather than updates. Once the data is stored in a database, most use cases require querying this data in real-time to uncover insights on the data quickly. DevOps teams will set real-time alerts to detect anomalies in server metrics such as CPU or memory. E-commerce websites need to understand buyers’ behavior to gather new insights and optimize their stock. A fintech company will want to detect fraud as transactions occur.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automated partitioning management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Time partitions are created automatically as data arrives. In QuestDB, data is partitioned by time (hourly, daily, weekly or monthly). Slicing the data by time partitions makes time-based queries more efficient. Time-based queries will only lift the relevant time partitions from the disk rather than lifting the entire dataset. Partitioning also allows having multiple tiers of storage, where older partitions can be mounted into cold storage, which is cheaper and slower.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Downsampling and interpolation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Representing the data with a lower frequency. For example, shifting from a daily view to a monthly view. In order to facilitate such queries with SQL and make them less verbose, QuestDB built a native extension to ANSI SQL with the keyword SAMPLE BY. This SQL statement slices the dataset by a time interval (15 minutes in our example below) and runs aggregations for that time period. We can optionally fill values for those periods for which we have no results (interpolation, fill with null, default, etc.)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hGOC5Qwc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t8um9xkcr6nm4ryutcmc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hGOC5Qwc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t8um9xkcr6nm4ryutcmc.png" alt="downsampling with SAMPLE BY SQL query" width="880" height="241"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Interval search&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fast retrieving data over arbitrary intervals. For example, zooming into a specific timeframe preceding a monitoring alert to better understand the underlying cause in real-time. QuestDB’s WHERE filter and IN time modifier for timestamp search is fast and efficient. The SQL query below retrieves all the data points in June 2018 for the column pickup_datetime:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oG0EN3UG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j89cstwkf2yj7v5ppe8u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oG0EN3UG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j89cstwkf2yj7v5ppe8u.png" alt="SQL query for interval search" width="880" height="143"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Time series joins&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Align join time-series data from two different tables, which do not have exactly matching timestamps. These are known as ASOF joins, which we have elaborated in the ASOF JOIN section in our documentation. Below, the two tables, trips and weather, each show values for given timestamps. However, the timestamps for each table are not equal. For each timestamp in trips, ASOF finds the nearest timestamp in weather and shows the associated weather value in the result table:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--whLst5_d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8mma103kbbkjfbjfqj73.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--whLst5_d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8mma103kbbkjfbjfqj73.png" alt="ASOF join SQL query" width="880" height="185"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Most recent first&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With time-series data, the most recent data is often more likely to be analyzed. QuestDB’s SQL language extension includes LATEST ON to get the most recent view of a record instantly. As data is ingested in chronological order, QuestDB starts scanning from the bottom and can thus retrieve the data point fast.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RH8BL1fg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0f0bzjfa0petyt5rla7m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RH8BL1fg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0f0bzjfa0petyt5rla7m.png" alt="most recent first LATEST ON SQL query" width="880" height="154"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Streaming ingestion protocols&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As time-series data is mostly machine data, it is produced and streamed to a database in a continuous fashion. The ability to sustain streamed data rather than in slow batches quickly becomes a must. The InfluxDB line protocol is very efficient and offers a lot of flexibility. For example, you can create new columns on the fly without specifying a schema ahead of time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why we set out to build QuestDB
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Democratizing time-series data performance
&lt;/h3&gt;

&lt;p&gt;Our CTO worked in electronic trading and had built trading infrastructure for more than 10 years. In 2013, his boss would not allow him to use the only high-performance database suited to deal with time-series data because of its proprietary nature and price.&lt;/p&gt;

&lt;p&gt;QuestDB was built with the intention to democratize the performance that was only available for high-end enterprise applications and make the tooling available for every developer around the world leveraging an open-source distribution model. Instead of writing a new querying language from scratch, our CTO decided to facilitate developer adoption via SQL rather than a complex proprietary language.&lt;/p&gt;

&lt;p&gt;And this was the origin of QuestDB.&lt;/p&gt;

&lt;p&gt;We have heard a large number of companies complaining about the performance limitations of open-source time-series databases. Most of those reuse existing libraries or are an extension of a well-known database that was not designed to process time-series data efficiently in the first place.&lt;/p&gt;

&lt;p&gt;Instead, we chose an alternative route, one that took more than 7 years of R&amp;amp;D. Our vision from day 1 was to challenge the norm and build software that uses new approaches and leverages the techniques learned in low-latency trading floors. An important aspect was to study and understand the evolution of hardware to build database software that could extract more performance from CPUs, memory, and modern hard disks.&lt;/p&gt;

&lt;h3&gt;
  
  
  QuestDB design and performance
&lt;/h3&gt;

&lt;p&gt;QuestDB is built-in zero-GC Java and C++, and every single algorithm in the code base has been written from scratch with the goal of maximizing performance.&lt;/p&gt;

&lt;p&gt;QuestDB’s data model (time-based arrays) differs from the LSM-tree or B-tree based storage engines found in InfluxDB or TimescaleDB. It reduces overhead and data duplication while maintaining immediate consistency and persisting data on disk.&lt;/p&gt;

&lt;p&gt;This linear data model structure massively optimizes ingestion as it allows the database to slice data extremely efficiently in small chunks and process it all in parallel. QuestDB also saturates the network cards to process messages from several senders in parallel. Our ingestion is append-only, with constant complexity, i.e. O(1); QuestDB does not rely on computationally intense indices to reorder data as it hits the database. Out-of-order ingests are dealt with and re-ordered in memory before being persisted to disk.&lt;/p&gt;

&lt;p&gt;QuestDB’s data layout enables CPUs to access data faster. With respect to queries, our codebase leverages modern CPU architecture with SIMD instructions to enable the same operation to be performed on multiple data elements in parallel. We store data in columns and partition it by time in order to lift the minimal amount of data from the disk for a given query.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--13o6bc14--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/gweyj0w3nzhbifmxk5hs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--13o6bc14--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/gweyj0w3nzhbifmxk5hs.png" alt="Data stored in columns and partitioned by time" width="880" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We didn't get everything right from the start! In 2021, we shipped QuestDB 6.0 to support high performance out-of-order data. A few months ago, we shipped dynamic commits to optimize ingestion throughput and data freshness for reads. We also rewrote our ingestion layer to make it more performant — taking advantage of the latest OS kernel innovations — and released official clients in seven programming languages to improve the developer experience. We are in the middle of decoupling data ingestion from table writers to eliminate table locks when using the Postgres wire protocol. We already have some ideas to make downsampling and aggregation queries even faster.&lt;/p&gt;

&lt;h3&gt;
  
  
  Additional resources on time-series data and databases
&lt;/h3&gt;

&lt;p&gt;To learn more about time-series data:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.g2.com/categories/time-series-databases"&gt;Best Time Series Databases&lt;/a&gt;&lt;br&gt;
&lt;a href="https://db-engines.com/en/ranking/time+series+dbms"&gt;DB-Engines Ranking of Time Series DBMS&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=A8uMF64rbS8&amp;amp;ab_channel=CodetotheMoon"&gt;Code to the Moon featuring QuestDB&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.allthingsdistributed.com/2021/06/amazon-timestream-time-series-is-the-new-black.html"&gt;Amazon Timestream - Time series is the new black&lt;/a&gt;&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/Time_series"&gt;Time series on Wikipedia&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To learn more about relevant projects:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://scikit-learn.org/stable/auto_examples/applications/plot_stock_market.html"&gt;Visualizing the stock market structure&lt;/a&gt;&lt;br&gt;
&lt;a href="https://research.facebook.com/blog/2017/2/prophet-forecasting-at-scale/"&gt;Prophet: forecasting at scale&lt;/a&gt;&lt;br&gt;
&lt;a href="https://builtin.com/data-science/time-series-forecasting-python"&gt;A Guide to Time Series Forecasting in Python&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The original post was published on &lt;a href="https://questdb.io/blog/time-series-data"&gt;QuestDB's blog&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>database</category>
      <category>opensource</category>
      <category>sql</category>
    </item>
    <item>
      <title>QuestDB announces Grafana support</title>
      <dc:creator>Nicolas Hourcard</dc:creator>
      <pubDate>Mon, 26 Oct 2020 15:35:38 +0000</pubDate>
      <link>https://dev.to/questdb/questdb-announces-grafana-support-1157</link>
      <guid>https://dev.to/questdb/questdb-announces-grafana-support-1157</guid>
      <description>&lt;p&gt;Hi all,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/questdb/questdb"&gt;QuestDB&lt;/a&gt; is a fast SQL time-series database. We have done our &lt;a href="https://news.ycombinator.com/item?id=23975807"&gt;HackerNews launch&lt;/a&gt; a few months ago and our &lt;a href="http://try.questdb.io:9000/"&gt;live demo&lt;/a&gt; with 1.6 billion rows from a well known NYC taxi dataset is still up and running!&lt;/p&gt;

&lt;p&gt;We announce QuestDB 4.0.4 with Grafana support, better postgreSQL compatibility and authentification for InfluxDB line protocol.&lt;/p&gt;

&lt;p&gt;Hit us with any questions, and bear with us until we release out of order inserts.&lt;/p&gt;

&lt;p&gt;The original blog post about building a Grafana dashboard on QuestDB is on &lt;a href="https://dzone.com/articles/build-a-monitoring-dashboard-with-questdb-and-graf"&gt;QuestDB's blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>database</category>
      <category>opensource</category>
      <category>devops</category>
      <category>sql</category>
    </item>
    <item>
      <title>How we made our SQL database QuestDB even faster and more accurate</title>
      <dc:creator>Nicolas Hourcard</dc:creator>
      <pubDate>Fri, 29 May 2020 14:55:14 +0000</pubDate>
      <link>https://dev.to/nicquestdb/how-we-made-our-sql-database-questdb-even-faster-and-more-accurate-4558</link>
      <guid>https://dev.to/nicquestdb/how-we-made-our-sql-database-questdb-even-faster-and-more-accurate-4558</guid>
      <description>&lt;p&gt;See our article &lt;a href="https://questdb.io/blog/2020/05/12/interesting-things-we-learned-about-sums"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;About a month ago, we posted about using SIMD instructions to make aggregation calculations faster.&lt;/p&gt;

&lt;p&gt;Many comments suggested that we implement compensated summation (aka Kahan) as the naive method could produce inaccurate and unreliable results. This is why we spent some time integrating kahan and Neumaier summation algorithms. This post summarises a few things we learned along this journey.&lt;/p&gt;

&lt;p&gt;We thought Kahan would badly affect the performance since it uses 4x as many operations as the naive approach. However, some comments also suggested we could use prefetch and co-routines to pull the data from RAM to cache in parallel with other CPU instructions. We got phenomenal results thanks to these suggestions, with Kahan sums nearly as fast as the naive approach.&lt;/p&gt;

&lt;p&gt;A lot of you also asked if we could compare this with Clickhouse. As they implement Kahan summation, we ran a quick comparison. Here's what we got for summing 1bn doubles with nulls with Kahan algo. The details of how this was done are in the post.&lt;/p&gt;

&lt;p&gt;QuestDB: 68ms Clickhouse: 139ms&lt;/p&gt;

&lt;p&gt;Thanks for reading and please leave us a star if you find the project interesting!&lt;/p&gt;

&lt;p&gt;Nic&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>java</category>
      <category>database</category>
      <category>sql</category>
    </item>
    <item>
      <title>QuestDB - fast relational time-series DB, zero GC java</title>
      <dc:creator>Nicolas Hourcard</dc:creator>
      <pubDate>Mon, 02 Dec 2019 17:06:52 +0000</pubDate>
      <link>https://dev.to/nicquestdb/questdb-fast-relational-time-series-db-zero-gc-java-hhi</link>
      <guid>https://dev.to/nicquestdb/questdb-fast-relational-time-series-db-zero-gc-java-hhi</guid>
      <description>&lt;p&gt;Hi all,&lt;/p&gt;

&lt;p&gt;We have just released QuestDB open source (apache 2.0), and we would welcome your feedback. &lt;/p&gt;

&lt;p&gt;QuestDB is an open-source NewSQL relational database designed to process time-series data, faster. Our approach comes from low-latency trading; QuestDB’s stack is engineered from scratch, zero-GC Java and dependency-free.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.questdb.io/"&gt;https://www.questdb.io/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/questdb/questdb"&gt;https://github.com/questdb/questdb&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;thanks&lt;/p&gt;

&lt;p&gt;Nic&lt;/p&gt;

</description>
      <category>database</category>
      <category>java</category>
      <category>opensource</category>
      <category>sql</category>
    </item>
  </channel>
</rss>
