DuckDB 允许附加(Attach)到数据库文件以及从数据库文件分离(Detach)。
示例
附加数据库 file.db,别名由文件名推断得出(即 file)
ATTACH 'file.db';
附加数据库 file.db,并使用显式别名(file_db)
ATTACH 'file.db' AS file_db;
以只读模式附加数据库 file.db
ATTACH 'file.db' (READ_ONLY);
以 16 kB 的块大小附加数据库 file.db
ATTACH 'file.db' (BLOCK_SIZE 16_384);
以 2048 行的行组大小附加数据库 file.db
ATTACH 'file.db' (ROW_GROUP_SIZE 2048);
附加一个用于读写的 SQLite 数据库(更多信息请参阅 sqlite 扩展)
ATTACH 'sqlite_file.db' AS sqlite_db (TYPE sqlite);
如果推断的数据库别名 file 尚不存在,则附加数据库 file.db
ATTACH IF NOT EXISTS 'file.db';
如果显式数据库别名 file_db 尚不存在,则附加数据库 file.db
ATTACH IF NOT EXISTS 'file.db' AS file_db;
将数据库 file2.db 附加为别名 file_db,如果该别名已存在则先分离并替换之
ATTACH OR REPLACE 'file2.db' AS file_db;
在别名为 file 的附加数据库中创建一个表
CREATE TABLE file.new_table (i INTEGER);
分离别名为 file 的数据库
DETACH file;
显示所有已附加数据库的列表
SHOW DATABASES;
将默认数据库更改为 file 数据库
USE file;
ATTACH
ATTACH 语句将一个新的数据库文件添加到目录中,以便对其进行读写。请注意,附加定义不会在会话之间持久保存:当启动新会话时,您必须重新附加到所有数据库。
ATTACH 语法
ATTACH 允许 DuckDB 操作多个数据库文件,并允许在不同数据库文件之间传输数据。
ATTACH 支持 HTTP 和 S3 端点。对于这些端点,默认情况下它会创建一个只读连接。因此,以下两条命令是等效的
ATTACH 'https://blobs.duckdb.org/databases/stations.duckdb' AS stations_db;
ATTACH 'https://blobs.duckdb.org/databases/stations.duckdb' AS stations_db (READ_ONLY);
同样,以下两条连接到 S3 的命令是等效的
ATTACH 's3://blobs-duckdb/databases/stations.duckdb' AS stations_db;
ATTACH 's3://blobs-duckdb/databases/stations.duckdb' AS stations_db (READ_ONLY);
显式存储版本
DuckDB v1.2.0 引入了 STORAGE_VERSION 选项,允许显式指定存储版本。使用此选项,您可以选择加入更新的、前向不兼容的功能
ATTACH 'file.db' (STORAGE_VERSION 'v1.2.0');
此设置指定了能够读取该数据库文件的最低 DuckDB 版本。当使用此选项写入数据库文件时,生成的那些文件无法被低于指定版本的旧版 DuckDB 打开。它们可以被指定版本以及所有更高版本的 DuckDB 读取。
更多详细信息,请参阅 “存储”页面。
数据库加密
DuckDB 支持数据库加密。默认情况下,它使用 AES 加密,密钥长度为 256 位,并使用推荐的 GCM 模式。加密涵盖主数据库文件、预写日志(WAL)文件,甚至临时文件。要附加到加密数据库,请使用带有 ENCRYPTION_KEY 的 ATTACH 语句。
ATTACH 'encrypted.db' AS enc_db (ENCRYPTION_KEY 'quack_quack');
为了加密数据,DuckDB 可以使用内置的 mbedtls 库,也可以使用来自 httpfs 扩展的 OpenSSL 库。请注意,由于硬件加速,OpenSSL 版本速度快得多,因此请确保加载 httpfs 以获得良好的加密性能
LOAD httpfs;
ATTACH 'encrypted.db' AS enc_db (ENCRYPTION_KEY 'quack_quack'); -- will be faster thanks to httpfs
要将 AES 模式更改为 CBC 或 CTR,请使用 ENCRYPTION_CIPHER 选项
ATTACH 'encrypted.db' AS enc_db (ENCRYPTION_KEY 'quack_quack', ENCRYPTION_CIPHER 'CBC');
ATTACH 'encrypted.db' AS enc_db (ENCRYPTION_KEY 'quack_quack', ENCRYPTION_CIPHER 'CTR');
数据库加密意味着使用 存储版本 1.4.0 或更高版本。
DuckDB 的加密尚未完全符合官方的 NIST 要求。请关注议题
#20162“Store and verify tag for canary encryption” 以跟踪我们迈向符合 NIST 标准的进展。
选项
在 ATTACH 语句后的括号内可以提供零个或多个复制选项。参数值可以通过单引号包裹或不包裹传入。参数值可以使用任意表达式。
| 名称 | 描述 | 类型 | 默认值 |
|---|---|---|---|
ACCESS_MODE |
数据库的访问模式(AUTOMATIC、READ_ONLY 或 READ_WRITE)。 |
VARCHAR |
automatic |
COMPRESS |
数据库是否被压缩。仅适用于内存数据库。 | VARCHAR |
false |
TYPE |
文件类型(DUCKDB 或 SQLITE),或者根据输入字符串字面量推导(MySQL、PostgreSQL)。 |
VARCHAR |
DUCKDB |
BLOCK_SIZE |
新数据库文件的块大小。必须是 2 的幂且在 [16384, 262144] 范围内。现有文件无法设置此项。 | UBIGINT |
262144 |
ROW_GROUP_SIZE |
新数据库文件的行组大小。 | UBIGINT |
122880 |
STORAGE_VERSION |
所使用的存储版本。 | VARCHAR |
v1.0.0 |
ENCRYPTION_KEY |
用于加密数据库的加密密钥。 | VARCHAR |
- |
ENCRYPTION_CIPHER |
用于加密数据库的加密算法(CBC、CTR 或 GCM)。 |
VARCHAR |
- |
DETACH
DETACH 语句允许关闭并分离先前附加的数据库文件,从而释放对该数据库文件持有的任何锁。
请注意,无法分离默认数据库:如果您想这样做,请执行 USE 语句将默认数据库更改为另一个。例如,如果您连接到一个持久数据库,可以通过执行以下命令切换到内存数据库
ATTACH ':memory:' AS memory_db;
USE memory_db;
警告:关闭连接(例如在 Python 中调用
close()函数)不会释放对数据库文件持有的锁,因为文件句柄由 DuckDB 主实例(在 Python 的情况下为duckdb模块)持有。
DETACH 语法
名称限定
目录对象的全限定名称包含对象的目录(catalog)、架构(schema)和名称(name)。例如
附加数据库 new_db
ATTACH 'new_db.db';
在数据库 new_db 中创建架构 my_schema
CREATE SCHEMA new_db.my_schema;
在架构 my_schema 中创建表 my_table
CREATE TABLE new_db.my_schema.my_table (col INTEGER);
引用表 my_table 中的列 col
SELECT new_db.my_schema.my_table.col FROM new_db.my_schema.my_table;
请注意,通常不需要全限定名称。当名称不是全限定时,系统会使用目录搜索路径(catalog search path)来查找要引用的条目。默认的目录搜索路径包括系统目录、临时目录以及最初附加的数据库,以及 main 架构。
另请注意关于 标识符和数据库名称的具体规则。
默认数据库和架构
当创建表而不进行任何限定时,该表将在默认数据库的默认架构中创建。默认数据库是系统启动时加载的数据库,而默认架构是 main。
在默认数据库中创建表 my_table
CREATE TABLE my_table (col INTEGER);
更改默认数据库和架构
可以使用 USE 命令更改默认数据库和架构。
将默认数据库架构设置为 new_db.main
USE new_db;
将默认数据库架构设置为 new_db.my_schema
USE new_db.my_schema;
解决冲突
当仅提供单个限定符时,只要没有冲突,系统就可以将其解释为目录或架构。例如
ATTACH 'new_db.db';
CREATE SCHEMA my_schema;
创建表 new_db.main.tbl
CREATE TABLE new_db.tbl (i INTEGER);
创建表 default_db.my_schema.tbl
CREATE TABLE my_schema.tbl (i INTEGER);
如果我们创建了一个冲突(即我们同时拥有一个同名的架构和一个同名的目录),系统要求使用全限定路径
CREATE SCHEMA new_db;
CREATE TABLE new_db.tbl (i INTEGER);
Binder Error:
Ambiguous reference to catalog or schema "new_db" - use a fully qualified path like "memory.new_db"
更改目录搜索路径
可以通过设置 search_path 配置选项来调整目录搜索路径,该选项使用逗号分隔的值列表。以下示例演示了在两个数据库中进行搜索
ATTACH ':memory:' AS db1;
ATTACH ':memory:' AS db2;
CREATE table db1.tbl1 (i INTEGER);
CREATE table db2.tbl2 (j INTEGER);
使用全限定名称引用表
SELECT * FROM db1.tbl1;
SELECT * FROM db2.tbl2;
或者设置搜索路径并使用名称引用表
SET search_path = 'db1,db2';
SELECT * FROM tbl1;
SELECT * FROM tbl2;
事务语义
当在多个数据库上运行查询时,系统会为每个数据库打开单独的事务。事务默认是惰性(lazily)启动的——当查询中第一次引用某个特定数据库时,该数据库的事务才会启动。可以通过设置 SET immediate_transaction_mode = true 来更改此行为,改为在所有已附加数据库中立即启动事务。
虽然可以同时激活多个事务,但系统只支持在单个事务中写入单个已附加的数据库。如果您尝试在单个事务中写入多个已附加的数据库,则会抛出以下错误
Attempting to write to database "db2" in a transaction that has already modified database "db1" -
a single transaction can only write to a single attached database.
此限制的原因是系统不维护跨附加数据库的事务原子性。事务仅在每个数据库文件内部是原子的。通过限制全局事务只能写入单个数据库文件,可以保持原子性保证。