Опубликован выпуск СУБД DuckDB 0.9.0, сочетающей такие свойства SQLite, как компактность, возможность подключения в форме встраиваемой библиотеки, хранение БД в одном файле и удобный CLI-интерфейс, со средствами и оптимизациями для выполнения аналитических запросов, охватывающих значительную часть хранимых данных, например, выполняющих агрегирование всего содержимого таблиц или слияние нескольких больших таблиц. Код проекта распространяется под лицензией MIT. Разработка пока находится на стадии формирования экспериментальных выпусков, так как формат хранилища пока не стабилизирован и меняется от версии к версии.
В DuckDB предоставляется расширенный диалект языка SQL, включающий дополнительные возможности для обработки очень сложных и длительно выполняемых запросов. Поддерживается использование сложных типов (массивы, структуры, объединения) и возможность выполнения произвольных и вложенных коррелирующих подзапросов. Поддерживается одновременное выполнение нескольких запросов, выполнение запросов напрямую из файлов в формате CSV и Parquet. Имеется возможность импорта из СУБД PostgreSQL.
Помимо кода оболочки из SQLite проектом используется вынесенный в отдельную библиотеку парсер из PostgreSQL, компонент Date Math из MonetDB, своя реализация оконных функций (на базе алгоритма Segment Tree Aggregation), обработчик регулярных выражений на основе библиотеки RE2, собственные оптимизатор запросов, MVCC-механизм управления одновременным выполнением заданий (Multi-Version Concurrency Control), а также векторизированный движок выполнения запросов на базе алгоритма Hyper-Pipelining Query Execution, позволяющий в одной операции разом обрабатывать большие наборы значений.
Среди изменений в новом выпуске:
- Значительно повышена производительность агрегирования больших наборов данных при обработке запросов с выражениями “GROUP BY” или “DISTINCT”, а также реализована техника вытеснения части хэш-таблицы на диск, решающая проблему с завершением операции из-за нехватки памяти в ситуациях, когда используемая для агрегирования хэш-таблица не умещается в оперативную память. Например, время обработки запроса “SELECT COUNT(*) FROM (SELECT DISTINCT * FROM tbl);” для набора в 30 млн строк при наличии 10ГБ памяти снизилась с 8.52 до 2.91 секунд.
- Реализована возможность сжатия строковых и целочисленных данных перед выполнением операций сортировки и сгруппированного агрегирования, которая позволила значительно снизить потребление памяти (например, перед сортировкой значения упаковываются в объединённые строки, подобные “alice005, bob00003, eve00003, mallory7).
- Повышена производительность оконных функций. По сравнению с прошлым выпуском время выполнения теста оконных функций снизилось с 33.8 до 3.8 сек.
- Обеспечена автоматическая чистка полных групп строк при выполнении операции DELETE. Также реализовано усечение файла с БД (уменьшение его размера) после удаления данных, если удалённые группы строк находились в конце файла.
- Повышена эффективность хранения индексов ART, используемых для проверки первичного и внешнего ключей или уникальности. Например, по сравнению с прошлой версией размер тестового индекса уменьшился с 278MB до 78MB.
- Добавлена поддержка автоматической установки и загрузки официальных дополнений, которые помечены как заслуживающие доверия. Например, для использования дополнения json теперь достаточно написать duckdb.sql(“FROM ‘https://raw.githubusercontent.com/duckdb/duckdb/main/data/json/example_n.ndjson'”).
- Добавлена поддержка динамической загрузки дополнений на базе WebAssambly (DuckDB-WASM).
- Добавлено дополнение для AWS, предоставляющее возможности, использующие AWS SDK.
- Добавлено экспериментальное дополнение для чтения данных из хранилища Azure.
- В клиенте добавлена экспериментальная поддержка API PySpark.
- Добавлено экспериментальное дополнение для чтения таблиц в формате Apache Iceberg.
- Ужесточена проверка правил с автоматическим приведением типов. В случае использования разных имён при определении типа и при указании поля структуры теперь будет выводиться ошибка. Например в таблице, созданной как “СREATE TABLE structs(s STRUCT(i INT));” теперь не получится добавить элемент с другим именем “INSERT INTO structs VALUES ({‘k’: 42});”, так как имена “i” и “k” отличаются.