mysql 扩展允许 DuckDB 直接从运行中的 MySQL 实例读取数据或向其写入数据。可以直接查询底层 MySQL 数据库中的数据。可以将数据从 MySQL 表加载到 DuckDB 表中,反之亦然。
安装和加载
要安装 mysql 扩展,请运行
INSTALL mysql;
该扩展会在首次使用时自动加载。如果您希望手动加载它,请运行
LOAD mysql;
从 MySQL 读取数据
要使 MySQL 数据库对 DuckDB 可用,请使用带有 mysql 或 mysql_scanner 类型的 ATTACH 命令
ATTACH 'host=localhost user=root port=0 database=mysql' AS mysqldb (TYPE mysql);
USE mysqldb;
配置
连接字符串以一组 key=value 对的形式确定连接到 MySQL 的参数。未提供的任何选项都将根据下表替换为其默认值。连接信息也可以通过 环境变量 指定。如果没有明确提供选项,MySQL 扩展会尝试从环境变量中读取它。
| 设置 | 默认值 | 环境变量 |
|---|---|---|
| database | NULL | MYSQL_DATABASE |
| host | localhost | MYSQL_HOST |
| password | MYSQL_PWD | |
| port | 0 | MYSQL_TCP_PORT |
| socket | NULL | MYSQL_UNIX_PORT |
| user | 当前用户 | MYSQL_USER |
| ssl_mode | preferred | |
| ssl_ca | ||
| ssl_capath | ||
| ssl_cert | ||
| ssl_cipher | ||
| ssl_crl | ||
| ssl_crlpath | ||
| ssl_key |
通过 Secrets 进行配置
MySQL 连接信息也可以通过 secrets 指定。可以使用以下语法创建 secret。
CREATE SECRET (
TYPE mysql,
HOST '127.0.0.1',
PORT 0,
DATABASE mysql,
USER 'mysql',
PASSWORD ''
);
当调用 ATTACH 时,将使用来自 secret 的信息。我们可以将连接字符串留空,以使用存储在 secret 中的所有信息。
ATTACH '' AS mysql_db (TYPE mysql);
我们可以使用连接字符串覆盖个别选项。例如,要在使用相同凭据的同时连接到不同的数据库,我们可以通过以下方式仅覆盖数据库名称。
ATTACH 'database=my_other_db' AS mysql_db (TYPE mysql);
默认情况下,创建的 secret 是临时的。可以使用 CREATE PERSISTENT SECRET 命令 将 secret 持久化。持久化 secret 可跨会话使用。
管理多个 Secret
命名 secret 可用于管理到多个 MySQL 数据库实例的连接。可以在创建 secret 时为其命名。
CREATE SECRET mysql_secret_one (
TYPE mysql,
HOST '127.0.0.1',
PORT 0,
DATABASE mysql,
USER 'mysql',
PASSWORD ''
);
然后可以使用 ATTACH 中的 SECRET 参数显式引用该 secret。
ATTACH '' AS mysql_db_one (TYPE mysql, SECRET mysql_secret_one);
SSL 连接
ssl 连接参数 可用于建立 SSL 连接。下面是支持的参数说明。
| 设置 | 描述 |
|---|---|
| ssl_mode | 用于连接服务器的安全状态:disabled, required, verify_ca, verify_identity 或 preferred(默认值:preferred) |
| ssl_ca | 证书颁发机构 (CA) 证书文件的路径名 |
| ssl_capath | 包含受信任 SSL CA 证书文件的目录的路径名 |
| ssl_cert | 客户端公钥证书文件的路径名 |
| ssl_cipher | 允许用于 SSL 加密的加密算法列表 |
| ssl_crl | 包含证书吊销列表的文件的路径名 |
| ssl_crlpath | 包含证书吊销列表文件的目录的路径名 |
| ssl_key | 客户端私钥文件的路径名 |
读取 MySQL 表
MySQL 数据库中的表可以像普通的 DuckDB 表一样读取,但底层数据是在查询时直接从 MySQL 读取的。
SHOW ALL TABLES;
| name |
|---|
| signed_integers |
SELECT * FROM signed_integers;
| t | s | m | i | b |
|---|---|---|---|---|
| -128 | -32768 | -8388608 | -2147483648 | -9223372036854775808 |
| 127 | 32767 | 8388607 | 2147483647 | 9223372036854775807 |
| NULL | NULL | NULL | NULL | NULL |
为了防止系统持续从 MySQL 重新读取表(特别是对于大表),在 DuckDB 中创建 MySQL 数据库的副本可能是有意义的。
可以使用标准 SQL 将数据从 MySQL 复制到 DuckDB,例如
CREATE TABLE duckdb_table AS FROM mysqlscanner.mysql_table;
向 MySQL 写入数据
除了从 MySQL 读取数据外,还可以使用标准 SQL 查询创建表、向 MySQL 注入数据以及对 MySQL 数据库进行其他修改。
这允许您使用 DuckDB(例如)将存储在 MySQL 数据库中的数据导出到 Parquet,或将数据从 Parquet 文件读取到 MySQL 中。
下面是一个关于如何在 MySQL 中创建新表并将数据加载到其中的简要示例。
ATTACH 'host=localhost user=root port=0 database=mysqlscanner' AS mysql_db (TYPE mysql);
CREATE TABLE mysql_db.tbl (id INTEGER, name VARCHAR);
INSERT INTO mysql_db.tbl VALUES (42, 'DuckDB');
支持对 MySQL 表进行许多操作。所有这些操作都会直接修改 MySQL 数据库,后续操作的结果可以使用 MySQL 读取。请注意,如果不希望进行修改,可以以 READ_ONLY 属性运行 ATTACH,这可以防止对底层数据库进行修改。例如
ATTACH 'host=localhost user=root port=0 database=mysqlscanner' AS mysql_db (TYPE mysql, READ_ONLY);
支持的操作
以下是支持的操作列表。
CREATE TABLE
CREATE TABLE mysql_db.tbl (id INTEGER, name VARCHAR);
INSERT INTO
INSERT INTO mysql_db.tbl VALUES (42, 'DuckDB');
SELECT
SELECT * FROM mysql_db.tbl;
| id | name |
|---|---|
| 42 | DuckDB |
COPY
COPY mysql_db.tbl TO 'data.parquet';
COPY mysql_db.tbl FROM 'data.parquet';
您还可以使用 COPY FROM DATABASE 语句 创建数据库的完整副本
COPY FROM DATABASE mysql_db TO my_duckdb_db;
UPDATE
UPDATE mysql_db.tbl
SET name = 'Woohoo'
WHERE id = 42;
DELETE
DELETE FROM mysql_db.tbl
WHERE id = 42;
ALTER TABLE
ALTER TABLE mysql_db.tbl
ADD COLUMN k INTEGER;
DROP TABLE
DROP TABLE mysql_db.tbl;
CREATE VIEW
CREATE VIEW mysql_db.v1 AS SELECT 42;
CREATE SCHEMA 和 DROP SCHEMA
CREATE SCHEMA mysql_db.s1;
CREATE TABLE mysql_db.s1.integers (i INTEGER);
INSERT INTO mysql_db.s1.integers VALUES (42);
SELECT * FROM mysql_db.s1.integers;
| i |
|---|
| 42 |
DROP SCHEMA mysql_db.s1;
事务
CREATE TABLE mysql_db.tmp (i INTEGER);
BEGIN;
INSERT INTO mysql_db.tmp VALUES (42);
SELECT * FROM mysql_db.tmp;
这会返回
| i |
|---|
| 42 |
ROLLBACK;
SELECT * FROM mysql_db.tmp;
这会返回一个空表。
DDL 语句在 MySQL 中不是事务性的。
在 MySQL 中运行 SQL 查询
mysql_query 表函数
mysql_query 表函数允许您在附加的数据库中运行任意读取查询。mysql_query 接受要在其中执行查询的附加 MySQL 数据库的名称,以及要执行的 SQL 查询。返回查询结果。单引号字符串通过重复两次单引号进行转义。
mysql_query(attached_database::VARCHAR, query::VARCHAR)
例如
ATTACH 'host=localhost database=mysql' AS mysqldb (TYPE mysql);
SELECT * FROM mysql_query('mysqldb', 'SELECT * FROM cars LIMIT 3');
mysql_execute 函数
mysql_execute 函数允许在 MySQL 中运行任意查询,包括更新数据库架构和内容的语句。
ATTACH 'host=localhost database=mysql' AS mysqldb (TYPE mysql);
CALL mysql_execute('mysqldb', 'CREATE TABLE my_table (i INTEGER)');
设置
| 名称 | 描述 | 默认值 |
|---|---|---|
mysql_bit1_as_boolean |
是否将 BIT(1) 列转换为 BOOLEAN |
true |
mysql_debug_show_queries |
调试设置:将发送到 MySQL 的所有查询打印到 stdout | false |
mysql_experimental_filter_pushdown |
是否使用过滤下推(目前处于实验阶段) | false |
mysql_tinyint1_as_boolean |
是否将 TINYINT(1) 列转换为 BOOLEAN |
true |
架构缓存
为了避免持续从 MySQL 获取架构数据,DuckDB 会缓存架构信息(例如表的名称、列等)。如果通过与 MySQL 实例的不同连接对架构进行了更改(例如向表中添加了新列),则缓存的架构信息可能会过期。在这种情况下,可以执行函数 mysql_clear_cache 来清除内部缓存。
CALL mysql_clear_cache();