<?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>Forem: Erika</title>
    <description>The latest articles on Forem by Erika (@erikah).</description>
    <link>https://forem.com/erikah</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%2F929502%2F5b006fb2-bce1-423c-8df0-91f21bc531f4.jpg</url>
      <title>Forem: Erika</title>
      <link>https://forem.com/erikah</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/erikah"/>
    <language>en</language>
    <item>
      <title>Live Coding Session: From Kafka Streams to REST APIs in minutes</title>
      <dc:creator>Erika</dc:creator>
      <pubDate>Tue, 13 Dec 2022 11:21:40 +0000</pubDate>
      <link>https://forem.com/tinybirdco/live-coding-session-from-kafka-streams-to-rest-apis-in-minutes-3d63</link>
      <guid>https://forem.com/tinybirdco/live-coding-session-from-kafka-streams-to-rest-apis-in-minutes-3d63</guid>
      <description>&lt;p&gt;The week after Christmas and before New Year's is one of the best times to learn something.&lt;/p&gt;

&lt;p&gt;Sure you might be "working", but apart from the occasional on-call alert you're probably just sitting around the (home) office looking for something to do.&lt;/p&gt;

&lt;p&gt;Well, come learn something with Tinybird. On December 27th, Alasdair Brown and Jorge Gomez Sancha are running a deep dive on building analytics APIs from Kafka streams using Tinybird.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.tinybird.co/live-coding-sessions/from-kafka-streams-to-rest-apis?utm_source=Dev.to&amp;amp;utm_medium=Dev.to&amp;amp;utm_campaign=Q4-2022-kafka-live-coding"&gt;Click here for all the details and to register&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You'll learn how to...&lt;/p&gt;

&lt;p&gt;...persist events data into OLAP storage&lt;br&gt;
...filter, aggregate, and enrich your streams with SQL&lt;br&gt;
...publish your queries as low-latency REST APIs&lt;br&gt;
...add query parameters to your API endpoints&lt;br&gt;
...monitor endpoints performance &amp;amp; errors&lt;br&gt;
...determine when Tinybird or ksqldb are appropriate&lt;/p&gt;

&lt;p&gt;We guarantee it will be at least 2.4x more fun that twiddling your thumbs and at least 4.7x more fun than tearing down the Christmas lights. 🤪&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.tinybird.co/live-coding-sessions/from-kafka-streams-to-rest-apis?utm_source=Dev.to&amp;amp;utm_medium=Dev.to&amp;amp;utm_campaign=Q4-2022-kafka-live-coding"&gt;Join us&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>productivity</category>
      <category>database</category>
      <category>api</category>
    </item>
    <item>
      <title>ClickHouse Fundamentals: Part 2</title>
      <dc:creator>Erika</dc:creator>
      <pubDate>Tue, 22 Nov 2022 12:52:02 +0000</pubDate>
      <link>https://forem.com/tinybirdco/clickhouse-fundamentals-part-2-4ao4</link>
      <guid>https://forem.com/tinybirdco/clickhouse-fundamentals-part-2-4ao4</guid>
      <description>&lt;p&gt;&lt;strong&gt;Change table TTLs&lt;/strong&gt;&lt;br&gt;
You can modify the TTL of a table in ClickHouse by using ALTER TABLE...MODIFY TTL. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ALTER TABLE database.table MODIFY TTL event_date + INTERVAL 30 DAY;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, ClickHouse will rewrite all table partitions, including those not impacted by the TTL change. This can be a very expensive operation, especially for large tables.&lt;/p&gt;

&lt;p&gt;To avoid impacting the performance of our database, we can instead set materialize_ttl_after_modify to 0 and clear up old partitions manually.&lt;/p&gt;

&lt;p&gt;This avoids the huge performance impact of rewriting all table partitions, but does mean there is additional manual effort.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;set materialize_ttl_after_modify=0;
ALTER TABLE database.table MODIFY TTL event_date + INTERVAL 30 DAY;
ALTER TABLE database.table DROP PARTITION 202205;
ALTER TABLE database.table DROP PARTITION 202206;
ALTER TABLE database.table DROP PARTITION 202207;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Analyze local files with clickhouse-local&lt;/strong&gt;&lt;br&gt;
clickhouse-local is like running a temporary ClickHouse server that only lasts for your session. It's great for exploring local files to quickly experiment with data, without needing to set up a proper ClickHouse deployment.&lt;/p&gt;

&lt;p&gt;It's possible to use to clickhouse-local to analyze files of structured data directly from the local file system.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT count() FROM file('final.ndjson');

SELECT count()
FROM file('final.ndjson')

Query id: a0a1f4b5-40cb-4125-b68b-4ed978c41576

┌─count()─┐
│  100000 │
└─────────┘

1 row in set. Elapsed: 0.659 sec. Processed 55.38 thousand rows, 96.97 MB (84.04 thousand rows/s., 147.16 MB/s.)


SELECT countDistinct(public_ip) FROM file('final.ndjson');

SELECT countDistinct(public_ip)
FROM file('final.ndjson')

Query id: 21df7ca5-e3bf-4010-b2a0-bf8b854502d2

┌─uniqExact(public_ip)─┐
│                   71 │
└──────────────────────┘

1 row in set. Elapsed: 0.225 sec. Processed 77.53 thousand rows, 96.45 MB (345.22 thousand rows/s., 429.46 MB/s.)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can create tables from the local file if you want to do more than one analysis on the data. The table is destroyed when your clickhouse-local session ends.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE TABLE auxiliar Engine=MergeTree() ORDER BY tuple() AS SELECT * FROM file('final.ndjson');

CREATE TABLE auxiliar
ENGINE = MergeTree
ORDER BY tuple() AS
SELECT *
FROM file('final.ndjson')

Query id: a1732be5-a912-41a5-bf8e-e524db8f12f4

Ok.

0 rows in set. Elapsed: 0.486 sec. Processed 100.00 thousand rows, 161.88 MB (205.73 thousand rows/s., 333.03 MB/s.)


SHOW CREATE TABLE auxiliar;

SHOW CREATE TABLE auxiliar

Query id: dffbcd4b-2c08-4d07-916c-b8e1b668c202


│ CREATE TABLE _local.auxiliar
(
    `timestamp_iso8601` Nullable(DateTime64(9)),
    `host` Nullable(String),
    `public_ip` Nullable(String),
    `request_method` Nullable(String),
    `request_path` Nullable(String),
    `status` Nullable(Int64),
    `body_bytes_sent` Nullable(Int64),
    `request_length` Nullable(Int64),
    `first_byte` Nullable(Float64),
    `request_time` Nullable(Float64),
    `lambda_name` Nullable(String),
    `lambda_region` Nullable(String),
    `path_type` Nullable(String),
    `hit_level` Nullable(String),
    `hit_state` Nullable(String),
    `error_details` Nullable(String),
    `owner_id` Nullable(String),
    `project_id` Nullable(String),
    `target_path` Nullable(String),
    `deployment_plan` Nullable(String),
    `lambda_duration` Nullable(Float64),
    `lambda_billed_duration` Nullable(Int64),
    `lambda_memory_size` Nullable(Int64),
    `http_user_agent` Nullable(String),
    `full_vercel_id` Nullable(String),
    `dc` Nullable(String),
    `public_ip_country` Nullable(String),
    `public_ip_city` Nullable(String),
    `asn_id` Nullable(String),
    `asn_name` Nullable(String)
)
ENGINE = MergeTree
ORDER BY tuple()
SETTINGS index_granularity = 8192 │


1 row in set. Elapsed: 0.001 sec.

SELECT count(), status - status % 100 AS status_range FROM auxiliar GROUP BY status_range;

SELECT
    count(),
    status - (status % 100) AS status_range
FROM auxiliar
GROUP BY status_range

Query id: 2685e0d4-827a-4306-8598-5d6e589dbd15

┌─count()─┬─status_range─┐
│   74000 │          200 │
│    5000 │          400 │
│   21000 │          300 │
└─────────┴──────────────┘

3 rows in set. Elapsed: 0.015 sec.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Add a default value for new columns&lt;/strong&gt;&lt;br&gt;
When you add a new column to a table, ClickHouse will add it with the default value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE TABLE local
ENGINE = MergeTree
ORDER BY number AS
SELECT *
FROM numbers(1000000);

ALTER TABLE local
    ADD COLUMN IF NOT EXISTS `date` DateTime;

OPTIMIZE TABLE local FINAL; -- To speed up the mutation / lazy way to know it has finished

SELECT *
FROM local
LIMIT 10

Query id: b5fedb97-a1c8-475f-a674-0b1658c8e889

┌─number─┬────────────────date─┐
│      0 │ 1970-01-01 01:00:00 │
│      1 │ 1970-01-01 01:00:00 │
│      2 │ 1970-01-01 01:00:00 │
│      3 │ 1970-01-01 01:00:00 │
│      4 │ 1970-01-01 01:00:00 │
│      5 │ 1970-01-01 01:00:00 │
│      6 │ 1970-01-01 01:00:00 │
│      7 │ 1970-01-01 01:00:00 │
│      8 │ 1970-01-01 01:00:00 │
│      9 │ 1970-01-01 01:00:00 │
└────────┴─────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To change the default value for old rows you need to declare the default in the column definition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ALTER TABLE local
    ADD COLUMN IF NOT EXISTS `new_date` DateTime DEFAULT now();

OPTIMIZE TABLE local FINAL;

SELECT *
FROM local
LIMIT 10

Query id: b5ff3afd-78f7-4ea3-8d43-adc7fe14f0a0

┌─number─┬────────────────date─┬────────────new_date─┐
│      0 │ 1970-01-01 01:00:00 │ 2022-09-23 13:53:38 │
│      1 │ 1970-01-01 01:00:00 │ 2022-09-23 13:53:38 │
│      2 │ 1970-01-01 01:00:00 │ 2022-09-23 13:53:38 │
│      3 │ 1970-01-01 01:00:00 │ 2022-09-23 13:53:38 │
│      4 │ 1970-01-01 01:00:00 │ 2022-09-23 13:53:38 │
│      5 │ 1970-01-01 01:00:00 │ 2022-09-23 13:53:38 │
│      6 │ 1970-01-01 01:00:00 │ 2022-09-23 13:53:38 │
│      7 │ 1970-01-01 01:00:00 │ 2022-09-23 13:53:38 │
│      8 │ 1970-01-01 01:00:00 │ 2022-09-23 13:53:38 │
│      9 │ 1970-01-01 01:00:00 │ 2022-09-23 13:53:38 │
└────────┴─────────────────────┴─────────────────────┘

10 rows in set. Elapsed: 0.002 sec.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that this means that new rows will also get the default value if it's not declared on insertion.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ALTER TABLE local
    MODIFY COLUMN `new_date` DateTime DEFAULT yesterday();

INSERT INTO local(number) VALUES (999999999);

SELECT *
FROM local
WHERE number = 999999999

Query id: 02527ad6-4644-42ff-8755-8869a9df30fa

┌────number─┬────────────────date─┬────────────new_date─┐
│ 999999999 │ 1970-01-01 01:00:00 │ 2022-09-22 00:00:00 │
└───────────┴─────────────────────┴─────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>watercooler</category>
    </item>
    <item>
      <title>ClickHouse Fundamentals: Part 1</title>
      <dc:creator>Erika</dc:creator>
      <pubDate>Thu, 27 Oct 2022 13:20:55 +0000</pubDate>
      <link>https://forem.com/tinybirdco/clickhouse-fundamentals-part-1-125d</link>
      <guid>https://forem.com/tinybirdco/clickhouse-fundamentals-part-1-125d</guid>
      <description>&lt;p&gt;We've launched an &lt;a href="https://www.tinybird.co/clickhouse/knowledge-base/?utm_source=Dev.to&amp;amp;utm_medium=Dev.to&amp;amp;utm_campaign=Q4-2022-clickhouse"&gt;Open Source ClickHouse® Knowledge Base&lt;/a&gt;! &lt;/p&gt;

&lt;p&gt;We'll be sharing some of the tips here on Dev.to but if you don't want to wait, jump in and find them &lt;a href="https://www.tinybird.co/clickhouse/knowledge-base/?utm_source=Dev.to&amp;amp;utm_medium=Dev.to&amp;amp;utm_campaign=Q4-2022-clickhouse"&gt;all in one place&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Oh, and if you're a ClickHouse guru, please feel free to contribute your own ClickHouse magic.&lt;/p&gt;

&lt;p&gt;Here's part 1:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;View the intermediate states of aggregations&lt;/strong&gt;&lt;br&gt;
Using aggregation functions with the -State modifier (e.g. sumState) result in intermediate states being stored in ClickHouse. These intermediate states generally cannot be read, as they are stored in a binary representation. Thus, to read the result, we must use the corresponding -Merge modifer when selecting the result (e.g. sumMerge).&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT
    number % 4 AS pk,
    avgState(number) AS avg_state
FROM numbers(2000)
GROUP BY pk

Query id: af1c69e7-b5d2-4063-9b8d-1ac08598fc79

┌─pk─┬─avg_state─┐
│  0 │ 8��         │
│  1 │ ,��         │
│  2 │  ��         │
│  3 │ ��          │
└────┴───────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to explore the intermediate states, perhaps without knowing what the original aggregation method was, you can instead use the finalizeAggregation function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT
    pk,
    finalizeAggregation(avg_state)
FROM
(
    SELECT
        number % 4 AS pk,
        avgState(number) AS avg_state
    FROM numbers(2000)
    GROUP BY pk
)

Query id: 7cf3a07f-f5d1-4ddd-891f-a89bb304b227

┌─pk─┬─finalizeAggregation(avg_state)─┐
│  0 │                            998 │
│  1 │                            999 │
│  2 │                           1000 │
│  3 │                           1001 │
└────┴────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Apply column default to existing rows&lt;/strong&gt;&lt;br&gt;
ClickHouse includes a special wrapper type called Nullable which allows a column to contain null values. It's common to use this early on in schema design, when a default value has not yet been decided.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE TABLE deleteme
(
    `number` UInt64,
    `date` Nullable(DateTime)
)
ENGINE = MergeTree
PARTITION BY number % 10
ORDER BY number AS
SELECT
    number,
    NULL
FROM numbers(10)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, you will often find that you eventually want to modify this column to remove Nullable and insert a default value instead of nulls.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ALTER TABLE deleteme MODIFY COLUMN `date` DEFAULT now()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adding a default value will affect new rows, but will not replace the nulls in existing rows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT *
FROM deleteme
LIMIT 1;

┌─number─┬─date─┐
│      0 │ ᴺᵁᴸᴸ │
└────────┴──────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To apply the new default value to existing rows, you can use MATERIALIZE.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ALTER TABLE deleteme
MATERIALIZE COLUMN `date`;

SELECT *
FROM deleteme
LIMIT 1;

┌─number─┬────────────────date─┐
│      0 │ 2022-09-23 12:31:14 │
└────────┴─────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Avoid TOO_MANY_PARTS with async_insert&lt;/strong&gt;&lt;br&gt;
ClickHouse was originally designed to insert data in batches.&lt;/p&gt;

&lt;p&gt;For engineers accustomed to other databases, it's a common mistake to send hundreds of individual inserts per second to ClickHouse and get a TOO_MANY_PARTS error. This error is ClickHouse telling us to throttle ingestion, as it can't keep up.&lt;/p&gt;

&lt;p&gt;Until recently, you were required to solve this issue yourself, by buffering inserts and sending larger batches.&lt;/p&gt;

&lt;p&gt;However, ClickHouse v21.11 introduced async_insert which enables ClickHouse to handle batching small inserts for you.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;&lt;br&gt;
async_insert is disabled by default, so you must enable it to take advantage of this feature.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you decide to use it you should also have a look at async_insert_threads, async_insert_max_data_size, async_insert_busy_timeout_ms and wait_for_async_insert.&lt;/p&gt;

</description>
      <category>clickhouse</category>
      <category>opensource</category>
      <category>database</category>
      <category>performance</category>
    </item>
    <item>
      <title>When you should use columnar databases and not Postgres, MySQL, or MongoDB</title>
      <dc:creator>Erika</dc:creator>
      <pubDate>Tue, 25 Oct 2022 16:56:19 +0000</pubDate>
      <link>https://forem.com/tinybirdco/when-you-should-use-columnar-databases-and-not-postgres-mysql-or-mongodb-4ldl</link>
      <guid>https://forem.com/tinybirdco/when-you-should-use-columnar-databases-and-not-postgres-mysql-or-mongodb-4ldl</guid>
      <description>&lt;p&gt;&lt;em&gt;by &lt;a href="https://www.linkedin.com/in/javisantana/"&gt;Javier Santana&lt;/a&gt;, Co-founder at Tinybird&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Row-oriented, OLTP databases aren't ideal application DBs when you know you'll need to run analytics on lots of data. Choose OLAP instead.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you develop an application, your first choice for a database is often one of &lt;a href="https://www.postgresql.org/"&gt;Postgres&lt;/a&gt;, &lt;a href="https://www.mysql.com/"&gt;MySQL&lt;/a&gt;, or - if NoSQL is more your thing - &lt;a href="https://www.mongodb.com/"&gt;MongoDB&lt;/a&gt;. You can’t go wrong with any of these; they’re great general-purpose databases with huge communities and some excellent features (e.g. transactions) that make developers’ lives easier.&lt;/p&gt;

&lt;p&gt;But there comes a point when things start to slow down. So you read a few blog posts, scan some docs, browse some dev forums, and spend hours tuning and improving queries, database config, etc. This does improve things temporarily, but eventually, you hit a wall.&lt;/p&gt;

&lt;p&gt;If you cut your database teeth on the Postgres/MySQL zeitgeist, it’d be understandable if you thought that most applications should be built on these or similar databases; the row-oriented, OLTP approach lends itself well to most of the app development that’s happened over the last decade.&lt;/p&gt;

&lt;p&gt;But then you realize there are other databases out there focused specifically on analytical use cases with lots of data and complex queries. Newcomers like &lt;a href="https://github.com/ClickHouse"&gt;ClickHouse&lt;/a&gt;, &lt;a href="https://github.com/apache/pinot"&gt;Pinot&lt;/a&gt;, and &lt;a href="https://github.com/apache/druid"&gt;Druid&lt;/a&gt; (all open source) respond to a new class of problem: The need to develop applications using endpoints published on analytical queries that were previously confined only to the data warehouse and BI tools.&lt;/p&gt;

&lt;p&gt;To use a metaphor: if you want to find 3 specific trees in a massive forest, OLTP is great. But if you want to count all the trees? That’s where OLAP comes in.&lt;/p&gt;

&lt;p&gt;When you discover these new analytical databases, all the sudden your general-purpose database doesn’t feel so “general-purpose” anymore. And you realize that maybe Postgres, MySQL, and MongoDB aren’t the databases you’re looking for to tackle your next project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5QoIiaFi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2rgq3bzd4lcyd7rujj2k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5QoIiaFi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2rgq3bzd4lcyd7rujj2k.png" alt="These aren't the databases you're looking for" width="757" height="330"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But why?&lt;/strong&gt;&lt;br&gt;
Why can't every database be good for both transactional and analytical workloads? The answer is basic physics. Hardware has hard limits, and you have to configure it one way for transactional use cases, and another way for analytical ones.&lt;/p&gt;

&lt;p&gt;More specifically, it has to do with how data is physically stored and processed. Analytical databases like ClickHouse, for example, store data in a columnar fashion; all the values in a column in a table are stored together in disk. In OLTP databases, the data is stored by row, so all the values in a row stay together.&lt;/p&gt;

&lt;p&gt;And this is very important.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Analytical databases store data in columns. Traditional OLTP databases store it in rows. This makes a big difference.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Data locality matters.&lt;/strong&gt;&lt;br&gt;
If you go to the grocery store to buy 100 cans of soda, you hope to find them packaged in 12-packs all on the same shelf. You go to one place, grab the packs you need, check out, and you’re on to your next errand in 5 minutes tops.&lt;/p&gt;

&lt;p&gt;But if the cans are spread out all over the store, behind the bananas and beside the corn starch, you'd need to push your shopping cart from end to end to collect them all. You’d be lucky to get out of there before closing time.&lt;/p&gt;

&lt;p&gt;The same thing is true with data: If data sits together in disk or memory, reading and processing it is way faster. &lt;/p&gt;

&lt;p&gt;This is because disks and memory work 100 times faster if access is sequential. And CPUs process much faster if they don't need to jump between different tasks.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Disks, memory, and CPU work way faster when data is close together.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But of course, cans of soda aren’t data and it’s not fair to compare them. Cans of soda are physical objects, data is not. If the goal is a “faster checkout time”, then there are many things you can do with data to speed things up:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compress it&lt;/strong&gt;&lt;br&gt;
We all use compression to save data in our disks. If you are old like me you probably used winzip. In general, we all understand that if you compress data, it gets smaller. Typically speaking, smaller is better when storing things. It’s why fast food chains buy soda syrup and carbonated water in bulk instead of stacking hundreds of 12-packs next to the burger patties.&lt;/p&gt;

&lt;p&gt;Compression is a general term, and there are many ways to compress data. But there’s one thing common to all compression methods: compression works much better if similar values are together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vectorize it&lt;/strong&gt;&lt;br&gt;
Many years ago, video games started to use 3D graphics that required complex vector calculations to move things in a 3D space. Intel (the market leader) created MMX technology and later SSE to enable CPUs to do vector math quickly. So in one CPU cycle you do 3 operations instead of one. Vectorization lets CPUs process many values at the same time, but it's only possible if those values are stored together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cache it&lt;/strong&gt;&lt;br&gt;
In a somewhat famous slide titled “Numbers Everyone Should Know” (slide 13 in &lt;a href="http://static.googleusercontent.com/media/research.google.com/en/us/people/jeff/stanford-295-talk.pdf"&gt;this presentation&lt;/a&gt;), Jeff Dean lists retrieval times by data location. As you can see, L1 cache access is 200x faster than main memory access. If you cache, you go fast.&lt;/p&gt;

&lt;p&gt;And it turns out that caching really likes when the data is close together. Add this along with compression so you can fit more data into the cache, and you can feed the CPU that much faster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sort it&lt;/strong&gt;&lt;br&gt;
Sorting is another huge performance factor, especially for columnar databases. If the data is sorted by the columns you’ll be filtering on, everything speeds up. It compresses better, access is faster, and the data locality is much much better. Sorting also helps to improve algorithms like joins, order by, limit, and group by. Proper sorting can speed up queries by multiple orders of magnitude. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Parallelize it&lt;/strong&gt;&lt;br&gt;
One more thing: parallelization. It’s not unique to analytical databases, but it helps a lot when you have a lot of data, which is when you typically consider using an analytical database. There are several types of parallelization: inside the CPU (aka vectorization), across multiple CPUs, and even across multiple machines. I’ll talk about it more in a bit.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Because analytical use cases almost always involve aggregating and filtering on columns, running against data stored by column is much faster.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;All these factors combined, it’s pretty simple: Things go faster when the data you want to access is stored together. And because analytical use cases pretty much always involve aggregating and filtering on specific columns, running these queries against data stored by column is just much faster. The hardware is optimized to count all the “trees” in as few cycles as possible. This is the main reason why column-oriented analytical bases are better for analytics.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But it doesn’t stop at data locality&lt;/strong&gt;&lt;br&gt;
The low-level benefits of columnar data stores for analytics should be pretty clear at this point: Data locality to extract 100% of the hardware is huge for speeding up queries on large amounts of data involving aggregations and filters typical in analytical use cases. But it doesn’t stop there. Analytical databases have other properties that make them even more appealing for handling large amounts of data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Probabilistic data structures&lt;/strong&gt;&lt;br&gt;
When you run analytics, you often don’t need many things that OLTP databases offer. One of those things is exactness, especially on statistical calculations. That might not seem like a big deal, but if you’re building on top of an analytical databases, it has big implications.&lt;/p&gt;

&lt;p&gt;If you are allowed to have a small error in your statistics, say +/- 1%, it can mean much, much faster queries. Calculating unique values, for example, is very compute-intensive and requires a lot of memory. If you can get by with some error, you can use &lt;a href="https://en.wikipedia.org/wiki/Category:Probabilistic_data_structures"&gt;probabilistic data structures&lt;/a&gt; like &lt;a href="https://en.wikipedia.org/wiki/HyperLogLog"&gt;HyperLogLog&lt;/a&gt; that estimate unique values with less memory and less CPU.&lt;/p&gt;

&lt;p&gt;Eventual consistency is also important here; it’s not usually achievable on OLTP workloads, but it’s not a problem in analytics. When you have a lot of data, a single machine often isn’t enough to run your analytical workloads. Of course, you should always try to scale vertically if you can, but eventually you’ll need to put data on several machines (sharding and replication are the terms for this). &lt;/p&gt;

&lt;p&gt;This is a well-trodden path: Coordination in a distributed system is not hard and there are &lt;a href="https://www.amazon.com/s?k=distributed+systems&amp;amp;crid=2P1QM2U3OFKU9&amp;amp;sprefix=distributed+system%2Caps%2C94&amp;amp;ref=nb_sb_noss_1"&gt;numerous books written about it&lt;/a&gt;. So you can pretty easily set up a cluster with several machines to scale your reads and writes. But the benefits go beyond basic horizontal scaling.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Probabilistic data structures improve query performance when exactness isn't required, and they are highly parallelizable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I talked earlier about parallelization at different levels. It turns out that parallelization, distributed systems, and probabilistic data structures get along quite well.&lt;/p&gt;

&lt;p&gt;The same algorithms and methods used to parallelize a workload on many cores work well when you parallelize it on many machines. Probabilistic data structures themselves happen to be highly parallelizable as well.&lt;/p&gt;

&lt;p&gt;Analytical databases take advantage of this. ClickHouse, for example, has a number of non-exact functions like &lt;em&gt;uniq()&lt;/em&gt; and &lt;em&gt;quantileDeterministic()&lt;/em&gt; that deterministically estimate their respective statistics. As data volumes get bigger and bigger, this has a meaningful impact on query latency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Faster writes with LSM tree&lt;/strong&gt;&lt;br&gt;
An important component of analytical architecture is the &lt;a href="https://en.wikipedia.org/wiki/Log-structured_merge-tree"&gt;log-structured merge-tree&lt;/a&gt; (LSMT), a data structure that many new databases (and some “old”) use because it aligns well with how hardware works. &lt;/p&gt;

&lt;p&gt;ClickHouse, for example, uses an LSMT-like structure that lets you insert millions of rows per second without any problems.&lt;/p&gt;

&lt;p&gt;In a lot of analytical use cases, you don’t just need your queries to be fast, you also need them to query the freshest data. This is especially important for realtime use cases where you need to serve low-latency analytics on streaming data. Every millisecond counts. &lt;a href="https://archive.nytimes.com/www.nytimes.com/imagepages/2009/07/24/business/0724-webBIZ-trading.ready.html"&gt;Just ask the day traders&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Incremental rollups and materializations&lt;/strong&gt;&lt;br&gt;
Almost all databases support some form of materialized views. But in most databases, including Postgres, MySQL, and MongoDB, the materialized views need to be periodically and manually refreshed. Analytical databases, on the other hand, usually have special tables and structures to enable incremental materializations, rollups, and other kinds of aggregations. The result is faster queries over aggregations even on datasets with high-frequency inserts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Specialized functions for statistics and time series&lt;/strong&gt;&lt;br&gt;
It’s hard to find an analytical use case that doesn’t involve time series data, statistical functions, or both. Most OLAP database designers understood this, so they designed their DBMS with specialized functions for time series data and statistics. ClickHouse has a &lt;a href="https://clickhouse.com/docs/en/sql-reference/functions/date-time-functions"&gt;host of specialized functions&lt;/a&gt; for dealing with dates and times that you mostly don’t get with Postgres, for example.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;OLAP databases like ClickHouse come with functions and structures that are optimized for analytical use cases.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;They aren’t perfect, but you still need them.&lt;/strong&gt;&lt;br&gt;
Analytical databases aren’t perfect by any means. They’re often a huge pain, not necessarily because they are harder to manage, but, because they let you store and process way more data, things just get harder in general. More data, more problems.&lt;/p&gt;

&lt;p&gt;But maybe, as you approach your next project, you should stop thinking in terms of transactions, &lt;a href="https://jepsen.io/consistency/models/linearizable"&gt;linearizability&lt;/a&gt;, fast point queries, super advanced search indices, and the other trappings of OLTP databases.&lt;/p&gt;

&lt;p&gt;Instead, think about what the types of queries you’ll need to run and how much data you’ll have. If you need to do sums on billions of rows, you’re gonna want to go with a columnar, OLAP database.&lt;/p&gt;

</description>
      <category>database</category>
      <category>mysql</category>
      <category>mongodb</category>
      <category>postgres</category>
    </item>
    <item>
      <title>We launched an open source ClickHouse Knowledge Base</title>
      <dc:creator>Erika</dc:creator>
      <pubDate>Mon, 24 Oct 2022 15:12:02 +0000</pubDate>
      <link>https://forem.com/tinybirdco/we-launched-an-open-source-clickhouse-knowledge-base-afp</link>
      <guid>https://forem.com/tinybirdco/we-launched-an-open-source-clickhouse-knowledge-base-afp</guid>
      <description>&lt;p&gt;ClickHouse is an incredible database. We want to help our community learn how to better use it for realtime analytics.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sUXqgPzE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jxzd7mydw62rnhiyacb2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sUXqgPzE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jxzd7mydw62rnhiyacb2.png" alt="clickhouse knowledge base" width="880" height="604"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We are very excited to announce that we've launched an &lt;a href="https://www.tinybird.co/clickhouse/knowledge-base/"&gt;open source ClickHouse Knowledge Base&lt;/a&gt;. Please feel free to check it out, and if you are so inclined, contribute to the &lt;a href="https://github.com/tinybirdco/clickhouse_knowledge_base"&gt;public repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Tinybird is built on top of &lt;a href="https://github.com/ClickHouse/ClickHouse/"&gt;ClickHouse&lt;/a&gt;, and we employ several ClickHouse developers who contribute daily to the lightning-fast open-source database to make it… well… lightning-faster.&lt;/p&gt;

&lt;p&gt;In fact, our team has over 40 years of combined experience working with ClickHouse. Not bad for a database whose initial release was only 6 years ago.&lt;/p&gt;

&lt;p&gt;Over the course of the time that we’ve been building Tinybird and contributing to ClickHouse, we’ve learned a lot about the column-oriented OLAP. The more we know, the more we love. It’s a perfect analytical database to solve the problems that data companies are trying to solve right now: namely operationalizing complex analytical queries and building products on top of them.&lt;/p&gt;

&lt;p&gt;We’ve launched this knowledge base to celebrate our continued investment in the ClickHouse open source project, and to help our customers, friends, and the broader ClickHouse community make the most of this incredible OLAP powerhouse. We intend to add new tips almost daily.&lt;/p&gt;

&lt;p&gt;Feel free to check it out. If you learn something, please share it wherever you scroll. And if you’ve got some ClickHouse magic up your sleeve that you want to share, please contribute!&lt;/p&gt;

</description>
      <category>clickhouse</category>
      <category>database</category>
      <category>serverless</category>
      <category>sql</category>
    </item>
    <item>
      <title>Hackathon: Build a space-themed application (and win a MacBook)</title>
      <dc:creator>Erika</dc:creator>
      <pubDate>Wed, 28 Sep 2022 09:27:39 +0000</pubDate>
      <link>https://forem.com/tinybirdco/hackathon-build-a-space-themed-application-and-win-a-macbook-2l8j</link>
      <guid>https://forem.com/tinybirdco/hackathon-build-a-space-themed-application-and-win-a-macbook-2l8j</guid>
      <description>&lt;p&gt;Calling all explorers of new worlds to join the first ever Tinybird Hackathon. Your mission is simple: Build a space-themed application using Tinybird (and win some awesome prizes).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mission briefing&lt;/strong&gt;&lt;br&gt;
Location: Online&lt;br&gt;
Submission time: Due by 11:59 GMT on October 12th, 2022&lt;br&gt;
Supplies Required: &lt;a href="https://auth.tinybird.co/u/signup/identifier?state=hKFo2SBtWFNnTmoyNGNRR2RvMklfVl9QbEJSYUN1TGlmelotWqFur3VuaXZlcnNhbC1sb2dpbqN0aWTZIGJmTTkzRHVtNFkwRzUyNG92RGYybEtydkZnTzBaR2lUo2NpZNkgVDZleGNNbzhJS2d1dlV3NHZGTllmcWx0OXBlNm1zQ1U&amp;amp;utm_source=dev.to&amp;amp;utm_medium=dev.to&amp;amp;utm_campaign=Q3-2022-space-hackathon"&gt;Free Tinybird account&lt;/a&gt; &amp;amp; GitHub or GitLab account&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Briefing notes&lt;/strong&gt;&lt;br&gt;
Team Size: This is an individual challenge. You’re on your own, Space Ranger.&lt;/p&gt;

&lt;p&gt;Streaming Data: You can use your own data, or pull from &lt;a href="https://www.tinybird.co/events/tinybird-hackathon-resources?utm_source=dev.to&amp;amp;utm_medium=dev.to&amp;amp;utm_campaign=Q3-2022-space-hackathon"&gt;this list we’ve compiled&lt;/a&gt;. Data must not include any PII.&lt;/p&gt;

&lt;p&gt;No Limits: You may create anything as long as it uses Tinybird and is space-themed.&lt;/p&gt;

&lt;p&gt;Fresh Code: You must create something from scratch. Submissions may be subject to a code-review to be eligible to win.. This is to ensure that all code used is in fact fresh.&lt;/p&gt;

&lt;p&gt;Submissions: Log your submissions to Star Command on &lt;a href="https://www.tinybird.co/events/tinybird-hackathon?utm_source=dev.to&amp;amp;utm_medium=dev.to&amp;amp;utm_campaign=Q3-2022-space-hackathon"&gt;this page&lt;/a&gt;. Each submission should include a well-documented GitHub repo, a working demo app, and a 2-min video demonstration of the app.&lt;/p&gt;

&lt;p&gt;IP &amp;amp; Ownership: You own your IP and anything you create using Tinybird.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Judging criteria&lt;/strong&gt;&lt;br&gt;
Submissions will be judged subjectively by a panel of independent developers and data engineers. All of the following factors will be considered when judging whether you’ve completed your mission:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Functionality: Does it work?&lt;/li&gt;
&lt;li&gt;Documentation: Is it easy to understand what you did?&lt;/li&gt;
&lt;li&gt;Performance: Are queries optimized?&lt;/li&gt;
&lt;li&gt;Aesthetics: Does it look nice?&lt;/li&gt;
&lt;li&gt;Gravity: Does it pull us in with wonder and amazement?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Prizes&lt;/strong&gt;&lt;br&gt;
x1 Grad Prize: MacBook Air&lt;br&gt;
x2 Runner Ups: Keychron K2&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mission complete?&lt;/strong&gt; &lt;br&gt;
Submit your work on &lt;a href="https://www.tinybird.co/events/tinybird-hackathon?utm_source=dev.to&amp;amp;utm_medium=dev.to&amp;amp;utm_campaign=Q3-2022-space-hackathon"&gt;this page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is Tinybird?&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://www.tinybird.co/?utm_source=dev.to&amp;amp;utm_medium=dev.to&amp;amp;utm_campaign=Q3-2022-space-hackathon"&gt;Tinybird&lt;/a&gt; is a platform that lets you ingest data, shape it with SQL, and publish the results as REST APIs. There aren’t any SDKs or libraries to learn, just use whatever you’re comfortable with to interact with APIs over HTTP.&lt;/p&gt;

</description>
      <category>watercooler</category>
      <category>challenge</category>
      <category>sql</category>
    </item>
  </channel>
</rss>
