2025-02-05

Ankündigung von DuckDB 1.2.0

The DuckDB team

Um die neue Version zu installieren, besuchen Sie bitte die Installationsanleitung. Für die Release Notes siehe die Release-Seite.

Manche Pakete (Go, R, Java) brauchen ein paar Extra-Tage für das Release wegen der Reviews, die in den Release-Pipelines nötig sind.

Wir sind stolz, DuckDB 1.2.0 zu veröffentlichen. Dieses Release trägt den Codenamen „Histrionicus“ nach der gutaussehenden Kragenente (Histrionicus histrionicus), die „kalte, schnell fließende Gewässer in Nordamerika, Grönland, Island und Ostsibirien“ bewohnt.

Was ist neu in 1.2.0

Es gab weit zu viele Änderungen, um jede im Detail zu besprechen, wir möchten aber mehrere besonders wichtige und spannende Features hervorheben! Unten eine Zusammenfassung dieser neuen Features mit Beispielen.

Breaking Changes

Die Funktion random nutzt jetzt einen größeren State. Das heißt, sie ist jetzt noch zufälliger™. Durch diese Änderung erzeugen feste Seeds jetzt andere Werte als in den vorherigen DuckDB-Versionen.

map['entry'] liefert jetzt einen Wert statt einer Liste von Einträgen. Zum Beispiel liefert map(['k'], ['v'])['k'] jetzt 'v', während es zuvor ['v'] lieferte. Wir haben außerdem die Funktion map_extract_value eingeführt, die jetzt der Alias für den Klammeroperator [] ist. Wenn Sie eine Liste zurückgeben möchten, nutzen Sie die Funktion map_extract: map_extract(map(['k'], ['v']), 'k') = ['v'].

Die Indexierung von list_reduce ist korrigiert. Wird Indexierung in list_reduce angewendet, zeigt der Index auf den letzten Parameter der Lambda-Funktion und die Indexierung beginnt bei 1. Deshalb liefert list_reduce(['a', 'b'], lambda x, y, i: x || y || i) den Wert ab2.

Die Funktionen current_time und current_date beziehen sich jetzt auf die lokale Zeitzone. Das macht beide Funktionen kompatibel mit PostgreSQL, zum Preis, dass ICU geladen sein muss, um diese Funktionen und ihre Aliase get_current_time() und today() zu nutzen.

Explizite Storage-Versionen

DuckDB v1.2.0 liefert neue Kompressionsmethoden, sie sind aber noch nicht standardmäßig aktiviert, damit ältere DuckDB-Versionen Dateien lesen können, die DuckDB v1.2.0 erzeugt.

In der Praxis heißt das: DuckDB v1.2.0 kann Datenbankdateien lesen, die von früheren stabilen DuckDB-Versionen wie v1.0.0 geschrieben wurden. Nutzen Sie DuckDB v1.2.0 mit den Standardeinstellungen, können ältere Versionen Dateien lesen, die DuckDB v1.2.0 geschrieben hat.

Sie können neuere, vorwärtsinkompatible Features opt-in mit der folgenden Syntax:

ATTACH 'file.db' (STORAGE_VERSION 'v1.2.0');

Diese Einstellung legt die minimale DuckDB-Version fest, die die Datenbankdatei lesen können soll. Werden Datenbankdateien mit dieser Option geschrieben, können die resultierenden Dateien nicht von älteren DuckDB-Release-Versionen als der angegebenen Version geöffnet werden. Sie können von der angegebenen Version und allen neueren DuckDB-Versionen gelesen werden.

Wenn Sie DuckDB-Datenbanken attachen, können Sie die Storage-Versionen mit dem folgenden Befehl abfragen:

SELECT database_name, tags FROM duckdb_databases();

Das zeigt die Storage-Versionen:

┌───────────────┬───────────────────────────────────┐
│ database_name │ tags │
│ varchar │ map(varchar, varchar) │
├───────────────┼───────────────────────────────────┤
│ file1 │ {storage_version=v1.2.0} │
│ file2 │ {storage_version=v1.0.0 - v1.1.3} │
│ ... │ ... │
└───────────────┴───────────────────────────────────┘

Das heißt, file2 kann von früheren DuckDB-Versionen geöffnet werden, während file1 nur mit v1.2.0 (oder zukünftigen Versionen) kompatibel ist.

Um vom neuen Format ins alte Format zur Kompatibilität zu konvertieren, nutzen Sie die folgende Sequenz in DuckDB v1.2.0:

ATTACH 'file1.db';
ATTACH 'converted_file.db' (STORAGE_VERSION 'v1.0.0');
COPY FROM DATABASE file1 TO converted_file;

Indexierung

ALTER TABLE ... ADD PRIMARY KEY. Nach langer Zeit kann DuckDB endlich einen Primary Key zu einer bestehenden Tabelle hinzufügen 🎉. Es ist jetzt also möglich, Folgendes auszuführen:

CREATE TABLE tbl (id INTEGER);
INSERT INTO tbl VALUES (42);
ALTER TABLE tbl ADD PRIMARY KEY (id);

Übermäßig eifriges Constraint-Checking behoben. Wir haben außerdem ein langjähriges Issue mit übermäßig eifrigem Unique-Constraint-Checking behoben. Die folgende Befehlsfolge hat zum Beispiel früher einen Fehler geworfen, funktioniert jetzt aber:

CREATE TABLE students (id INTEGER PRIMARY KEY, name VARCHAR);
INSERT INTO students VALUES (1, 'John Doe');
BEGIN; -- start transaction
DELETE FROM students WHERE id = 1;
INSERT INTO students VALUES (1, 'Jane Doe');

CSV-Features

Latin-1- und UTF-16-Kodierungen. Zuvor war DuckDBs CSV-Reader auf UTF-8-Dateien beschränkt. Er kann jetzt Latin-1- und UTF-16-Dateien lesen. Zum Beispiel:

FROM read_csv('cities-latin-1.csv', encoding = 'latin-1');

Multi-Byte-Delimiter. DuckDB unterstützt jetzt Delimiter von bis zu 4 Bytes. Das heißt, Sie können endlich das Enten-Emoji als Spaltentrennzeichen nutzen. Zum Beispiel:

a🦆b
hello🦆world
FROM read_csv('example.dsv', sep = '🦆');

Strenges CSV-Parsing. Die RFC-4180-Spezifikation definiert Anforderungen an wohlgeformte CSV-Dateien, z. B. ein einzelnes Zeilentrennzeichen. Standardmäßig parst DuckDB CSVs jetzt im sogenannten Strict Mode (`strict_mode = true). Zum Beispiel wird die folgende CSV-Datei wegen gemischter Newline-Zeichen abgelehnt:

Terminal window
echo "a,b\r\nhello,42\nworld,84" > rfc_4180-defiant.csv
FROM read_csv('rfc_4180-defiant.csv');
Terminal window
Invalid Input Error:
Error when sniffing file "rfc_4180-defiant.csv".
It was not possible to automatically detect the CSV Parsing dialect/types

Mit der nachsichtigeren Option strict_mode = false wird sie aber geparst:

FROM read_csv('rfc_4180-defiant.csv', strict_mode = false);
┌─────────┬───────┐
│ a │ b │
│ varchar │ int64 │
├─────────┼───────┤
│ hello │ 42 │
│ world │ 84 │
└─────────┴───────┘

Performance-Verbesserungen. Der CSV-Parser im neuen Release nutzt einen neuen Algorithmus, um bei paralleler Ausführung eine neue Zeile zu finden. Das führt zu Speedups von rund 15 %.

Unbegrenzte Zeilenlänge. Zuvor war DuckDB auf CSV-Dateien mit Zeilen von bis zu 8 MB beschränkt. Die neue Version hebt diese Beschränkung auf, und Zeilen können beliebig lang sein.

Parquet-Features

Parquet-Dictionary- und Bloom-Filter-Unterstützung. DuckDB unterstützt jetzt das Schreiben vieler weiterer Typen mit Dictionary Encoding. Das sollte die Dateigröße in manchen Fällen reduzieren. DuckDB kann jetzt außerdem Parquet-Bloom-Filter lesen und schreiben. Bloom-Filter sind kleine Indexierungsdatenstrukturen, die genutzt werden können, um Row Groups auszuschließen, wenn ein Filter gesetzt ist. Das ist besonders nützlich für oft wiederholte, aber ungeordnete Daten (z. B. kategoriale Werte). Ein eigener Blogbeitrag folgt.

Delta-Binary-Packed-Kompression für Parquet. DuckDB unterstützt jetzt die Kompression DELTA_BINARY_PACKED sowie die Optionen DELTA_LENGTH_BYTE_ARRAY und BYTE_STREAM_SPLIT für Parquet-Dateien. Vor ein paar Wochen haben wir das in einem Blogbeitrag ausgeführt.

CLI-Verbesserungen

Safe Mode. Der DuckDB-Kommandozeilen-Client unterstützt jetzt den Safe Mode, der mit dem Flag -safe oder dem Dot-Command .safe_mode aktiviert werden kann. In diesem Modus wird der CLI-Client daran gehindert, auf externe Dateien außer der Datenbankdatei zuzugreifen, mit der er zunächst verbunden war, und daran, mit dem Host-Dateisystem zu interagieren. Mehr Informationen finden Sie auf der Seite „Securing DuckDB“ im Operations Manual.

Besseres Autocomplete. Das Autocomplete in der CLI nutzt jetzt eine Parsing Expression Grammar (PEG) für besseres Autocomplete sowie verbesserte Fehlermeldungen und Vorschläge.

Pretty-Printing großer Zahlen. Die CLI liefert eine Zusammenfassung der gedruckten Zahl, wenn der Client nur eine einzelne Zeile rendert.

SELECT 100_000_000 AS x, pi() * 1e9 AS y;
┌──────────────────┬───────────────────┐
│ x │ y │
│ int32 │ double │
├──────────────────┼───────────────────┤
│ 100000000 │ 3141592653.589793 │
│ (100.00 million) │ (3.14 billion) │
└──────────────────┴───────────────────┘

Friendly SQL

Präfix-Aliase. SQL-Ausdrucks- und Tabellenaliase können jetzt vor dem angegeben werden, worauf sie sich beziehen (statt der bekannten Syntax mit AS). Das kann in manchen Fällen die Lesbarkeit verbessern, zum Beispiel:

SELECT
e1: some_long_and_winding_expression,
e2: t2.a_column_name
FROM
t1: long_schema.some_long_table_name,
t2: short_s.tbl;

Die Idee geht auf Michael Toy zurück. Ein eigener Blogbeitrag folgt bald. Update: Der Blogbeitrag zu Präfix-Aliasen ist da.

RENAME-Klausel. DuckDB unterstützt jetzt die RENAME-Klausel in SELECT. Damit lassen sich Felder umbenennen, die der *-Ausdruck liefert:

CREATE TABLE integers (col1 INTEGER, col2 INTEGER);
INSERT INTO integers VALUES (42, 84);
SELECT * RENAME (col1 AS new_col1) FROM integers;

Star LIKE. Die Klauseln LIKE und SIMILAR TO können jetzt auf *-Ausdrücken als Kurzform für die COLUMNS-Syntax genutzt werden.

CREATE TABLE key_val (key VARCHAR, val1 INTEGER, val2 INTEGER);
INSERT INTO key_val VALUES ('v', 42, 84);
SELECT * LIKE 'val%' FROM key_val;
┌───────┬───────┐
│ val1 │ val2 │
│ int32 │ int32 │
├───────┼───────┤
│ 42 │ 84 │
└───────┴───────┘

Optimierungen

Wir haben viel Zeit in DuckDBs Optimizer gesteckt . Optimizer-Verbesserungen zu quantifizieren ist schwer, als Ergebnis dieser Optimierungen erreicht DuckDB zum Beispiel eine 13-%-Verbesserung der Gesamtlaufzeit der TPC-H-SF100-Queries auf einem MacBook Pro gegenüber dem vorherigen Release.

C-API für Extensions

Derzeit nutzen DuckDB-Extensions DuckDBs interne C++-Strukturen. Das – zusammen mit ein paar spaßigen Linking-Issues – erfordert eine Gleichschritt-Entwicklung von Extensions mit Mainline-DuckDB und ständige Updates. Ab diesem Release stellen wir eine neue C-artige API für Extensions in duckdb_extension.h bereit. Diese API kann genutzt werden, um zum Beispiel Scalar-, Aggregate- oder Table Functions in DuckDB zu erstellen. Es gibt zwei Hauptvorteile dieser API: Erstens haben viele Programmiersprachen (z. B. Go, Rust und sogar Java) direkte Bindings an C-APIs, was die Integration recht einfach macht. Zweitens ist die C Extension API stabil und rückwärtskompatibel, das heißt, Extensions, die diese API targeten, bleiben für neue DuckDB-Versionen funktionsfähig. Wir folgen mit einem neuen Extension-Template nach.

musl-Extensions

Verteilen von Extensions für musl. Die musl-C-Bibliothek wird oft in schlanken Setups wie Docker-Setups mit Alpine Linux genutzt. Ab diesem Release unterstützen wir musl offiziell und verteilen Extensions für die Plattform linux_amd64_musl (noch nicht für linux_arm64_musl). Hinweis: DuckDB-Binaries (z. B. der CLI-Client) werden für musl-Plattformen noch nicht verteilt, Sie müssen sie aus dem Quellcode bauen.

Zstd-Kompression

Spalten können jetzt mit Zstd-Kompression komprimiert werden, die für größere Strings geeignet ist. Standardmäßig wird diese Kompression nur für Strings länger als 4096 Zeichen in Betracht gezogen, das lässt sich aber mit der Einstellung zstd_min_string_length ändern.

Zstd-Kompression kann für eine Spalte explizit beim Anlegen der Tabelle aktiviert werden:

CREATE TABLE t (
v VARCHAR USING COMPRESSION 'zstd';
);

Schlussgedanken

Das waren ein paar Highlights – aber es gibt viele weitere Features und Verbesserungen in diesem Release. Es gab über 5 000 Commits von über 70 Contributors, seit wir 1.1.3 veröffentlicht haben. Die vollständigen – sehr langen – Release Notes finden Sie auf GitHub.

Wir möchten erneut unserer großartigen Community danken, die DuckDB nutzt, coole Projekte auf DuckDB baut und DuckDB verbessert, indem sie uns Feedback gibt. Ihre Beiträge bedeuten wirklich viel!