跳到主要内容

ATTACH and DETACH Statements

Goose 允许附加和分离数据库文件。

示例

附加数据库 file.db,别名由文件名自动推断为 file

ATTACH 'file.db';

附加数据库 file.db,并显式指定别名为 file_db

ATTACH 'file.db' AS file_db;

以只读模式附加数据库 file.db

ATTACH 'file.db' (READ_ONLY);

附加数据库 file.db,并将块大小设置为 16 kB:

ATTACH 'file.db' (BLOCK_SIZE 16_384);

附加数据库 file.db,并将 row group 大小设置为 2048 行:

ATTACH 'file.db' (ROW_GROUP_SIZE 2048);

附加一个可读写的 SQLite 数据库(更多信息见 sqlite extension):

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 语句会向 catalog 添加一个新的数据库文件,并允许对其进行读写。 请注意,附加定义不会在会话之间持久化:启动新会话后,需要重新附加所有数据库。

ATTACH 语法

ATTACH 允许 Goose 在多个数据库文件上操作,并在不同数据库文件之间传输数据。

ATTACH 支持 HTTP 和 S3 端点。对于这些端点,它默认创建只读连接。 因此,下面两条命令是等价的:

ATTACH 'https://${uri}/databases/stations.goose' AS stations_db;
ATTACH 'https://${uri}/databases/stations.goose' AS stations_db (READ_ONLY);

同样地,下面两条连接到 S3 的命令也是等价的:

ATTACH 's3://${uri}/databases/stations.goose' AS stations_db;
ATTACH 's3://${uri}/databases/stations.goose' AS stations_db (READ_ONLY);
ATTACH 'file.db' (STORAGE_VERSION 'v1.2.0');

该设置用于指定能够读取此数据库文件的最低 Goose 版本。使用该选项写出的数据库文件,无法被低于指定版本的 Goose 已发布版本打开;可被指定版本及更新版本读取。

更多细节请参阅“Storage” 页面

数据库加密

Goose 支持数据库加密。默认情况下,它使用 256 位密钥长度的 AES encryption,并采用推荐的 GCM 模式。加密范围覆盖主数据库文件、write-ahead-log (WAL) 文件,甚至临时文件。要附加加密数据库,请在 ATTACH 语句中使用 ENCRYPTION_KEY

ATTACH 'encrypted.db' AS enc_db (ENCRYPTION_KEY 'quack_quack');

为加密数据,Goose 可以使用内置的 mbedtls 库,或来自 httpfs extension 的 OpenSSL 库。请注意,由于硬件加速,OpenSSL 版本通常更快,因此建议加载 httpfs 以获得更好的加密性能:

LOAD httpfs;
ATTACH 'encrypted.db' AS enc_db (ENCRYPTION_KEY 'quack_quack'); -- will be faster thanks to httpfs

要将 AES 模式改为 CBCCTR,请使用 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 或更高版本的 storage version

Goose 的加密实现目前尚未满足官方 NIST requirements。 请关注 issue #20162 “Store and verify tag for canary encryption”,以跟踪我们在 NIST 合规方面的进展。

选项

ATTACH 语句后可通过括号提供零个或多个选项。参数值可以带单引号,也可以不带。参数值支持使用任意表达式。

名称描述类型默认值
ACCESS_MODE数据库的访问模式(AUTOMATICREAD_ONLYREAD_WRITE)。VARCHARautomatic
COMPRESS数据库是否压缩。仅适用于内存数据库。VARCHARfalse
TYPE文件类型(GOOSESQLITE),或根据输入字符串字面量推断(MySQL、PostgreSQL)。VARCHARGOOSE
BLOCK_SIZE新数据库文件的块大小。必须是 2 的幂,且位于 [16384, 262144] 范围内。不能用于已有文件。UBIGINT262144
ROW_GROUP_SIZE新数据库文件的 row group 大小。UBIGINT122880
STORAGE_VERSION使用的 storage 版本。VARCHARv1.0.0
ENCRYPTION_KEY用于加密数据库的密钥。VARCHAR-
ENCRYPTION_CIPHER用于加密数据库的加密算法(CBCCTRGCM)。VARCHAR-

DETACH

DETACH 语句可关闭并分离先前附加的数据库文件,释放该数据库文件上持有的锁。

请注意,不能直接分离默认数据库:如果你想这么做,请先执行 USE statement 将默认数据库切换为其他数据库。例如,如果当前连接的是持久化数据库,可以通过以下命令切换到内存数据库:

ATTACH ':memory:' AS memory_db;
USE memory_db;

警告:关闭连接(例如调用 Python 中的 close() function)并不会释放数据库文件上的锁,因为文件句柄由 Goose 主实例持有(在 Python 中即 goose 模块)。

DETACH 语法

名称限定

catalog 对象的完全限定名包含 catalogschema 和对象 name。例如:

附加数据库 new_db

ATTACH 'new_db.db';

在数据库 new_db 中创建 schema my_schema

CREATE SCHEMA new_db.my_schema;

在 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 来查找要引用的条目。默认 catalog search path 包含 system catalog、temporary catalog,以及初始附加数据库中的 main schema。

另请参阅关于标识符,尤其是数据库名称的规则。

默认数据库和 Schema

当创建表时未提供任何限定,表会创建在默认数据库的默认 schema 中。默认数据库是系统创建时启动的数据库,默认 schema 为 main

在默认数据库中创建表 my_table

CREATE TABLE my_table (col INTEGER);

更改默认数据库和 Schema

可以使用 USE 命令更改默认数据库和 schema。

将默认数据库 schema 设为 new_db.main

USE new_db;

将默认数据库 schema 设为 new_db.my_schema

USE new_db.my_schema;

解决冲突

当只提供单个限定名时,只要不存在冲突,系统可以将其解释为 catalogschema。例如:

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);

如果出现冲突(即 schema 和 catalog 同名),系统会要求改用完全限定路径:

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"

更改 Catalog Search Path

可以通过设置 search_path 配置项来调整 catalog 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;

事务语义

在多个数据库上运行查询时,系统会为每个数据库分别开启事务。默认采用_惰性_启动:当查询首次引用某个数据库时,才会为该数据库开启事务。可以切换 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.

该限制的原因是:系统无法保证跨已附加数据库事务的原子性。事务只在各自数据库文件_内部_保证原子性。通过限制全局事务只能写入单个数据库文件,才能维持原子性保证。