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 模式改为 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 或更高版本的 storage version。
Goose 的加密实现目前尚未满足官方 NIST requirements。 请关注 issue
#20162“Store and verify tag for canary encryption”,以跟踪我们在 NIST 合规方面的进展。
选项
在 ATTACH 语句后可通过括号提供零个或多个选项。参数值可以带单引号,也可以不带。参数值支持使用任意表达式。
| 名称 | 描述 | 类型 | 默认值 |
|---|---|---|---|
ACCESS_MODE | 数据库的访问模式(AUTOMATIC、READ_ONLY 或 READ_WRITE)。 | VARCHAR | automatic |
COMPRESS | 数据库是否压缩。仅适用于内存数据库。 | VARCHAR | false |
TYPE | 文件类型(GOOSE 或 SQLITE),或根据输入字符串字面量推断(MySQL、PostgreSQL)。 | VARCHAR | GOOSE |
BLOCK_SIZE | 新数据库文件的块大小。必须是 2 的幂,且位于 [16384, 262144] 范围内。不能用于已有文件。 | UBIGINT | 262144 |
ROW_GROUP_SIZE | 新数据库文件的 row group 大小。 | UBIGINT | 122880 |
STORAGE_VERSION | 使用的 storage 版本。 | VARCHAR | v1.0.0 |
ENCRYPTION_KEY | 用于加密数据库的密钥。 | VARCHAR | - |
ENCRYPTION_CIPHER | 用于加密数据库的加密算法(CBC、CTR 或 GCM)。 | VARCHAR | - |
DETACH
DETACH 语句可关闭并分离先前附加的数据库文件,释放该数据库文件上持有的锁。
请注意,不能直接分离默认数据库:如果你想这么做,请先执行 USE statement 将默认数据库切换为其他数据库。例如,如果当前连接的是持久化数据库,可以通过以下命令切换到内存数据库:
ATTACH ':memory:' AS memory_db;
USE memory_db;
警告:关闭连接(例如调用 Python 中的
close()function)并不会释放数据库文件上的锁,因为文件句柄由 Goose 主实例持有(在 Python 中即goose模块)。
DETACH 语法
名称限定
catalog 对象的完全限定名包含 catalog、schema 和对象 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;
解决冲突
当只提供单个限定名时,只要不存在冲突,系统可以将其解释为 catalog 或 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);
如果出现冲突(即 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.
该限制的原因是:系统无法保证跨已附加数据库事务的原子性。事务只在各自数据库文件_内部_保证原子性。通过限制全局事务只能写入单个数据库文件,才能维持原子性保证。