- 安装
- 文档
- 入门
- 连接
- 数据导入
- 客户端 API
- 概览
- ADBC
- C
- C++
- CLI
- Dart
- Go
- Java (JDBC)
- Julia
- Node.js (已弃用)
- Node.js (Neo)
- ODBC
- PHP
- Python
- R
- Rust
- Swift
- Wasm
- SQL
- 介绍
- 语句
- 概览
- ANALYZE
- ALTER TABLE
- ALTER VIEW
- ATTACH 和 DETACH
- CALL
- CHECKPOINT
- COMMENT ON
- COPY
- CREATE INDEX
- CREATE MACRO
- CREATE SCHEMA
- CREATE SECRET
- CREATE SEQUENCE
- CREATE TABLE
- CREATE VIEW
- CREATE TYPE
- DELETE
- DESCRIBE
- DROP
- EXPORT 和 IMPORT DATABASE
- INSERT
- LOAD / INSTALL
- PIVOT
- 性能分析
- SELECT
- SET / RESET
- SET VARIABLE
- SUMMARIZE
- 事务管理
- UNPIVOT
- UPDATE
- USE
- VACUUM
- 查询语法
- SELECT
- FROM 和 JOIN
- WHERE
- GROUP BY
- GROUPING SETS
- HAVING
- ORDER BY
- LIMIT 和 OFFSET
- SAMPLE
- 展开嵌套
- WITH
- WINDOW
- QUALIFY
- VALUES
- FILTER
- 集合操作
- 预处理语句
- 数据类型
- 表达式
- 函数
- 概览
- 聚合函数
- 数组函数
- 位字符串函数
- Blob 函数
- 日期格式化函数
- 日期函数
- 日期部分函数
- 枚举函数
- 间隔函数
- Lambda 函数
- 列表函数
- 映射函数
- 嵌套函数
- 数值函数
- 模式匹配
- 正则表达式
- 结构体函数
- 文本函数
- 时间函数
- 时间戳函数
- 带时区时间戳函数
- 联合函数
- 实用函数
- 窗口函数
- 约束
- 索引
- 元查询
- DuckDB 的 SQL 方言
- 示例
- 配置
- 扩展
- 核心扩展
- 概览
- 自动补全
- Avro
- AWS
- Azure
- Delta
- DuckLake
- 编码
- Excel
- 全文搜索
- httpfs (HTTP 和 S3)
- Iceberg
- ICU
- inet
- jemalloc
- MySQL
- PostgreSQL
- 空间
- SQLite
- TPC-DS
- TPC-H
- UI
- VSS
- 指南
- 概览
- 数据查看器
- 数据库集成
- 文件格式
- 概览
- CSV 导入
- CSV 导出
- 直接读取文件
- Excel 导入
- Excel 导出
- JSON 导入
- JSON 导出
- Parquet 导入
- Parquet 导出
- 查询 Parquet 文件
- 使用 file: 协议访问文件
- 网络和云存储
- 概览
- HTTP Parquet 导入
- S3 Parquet 导入
- S3 Parquet 导出
- S3 Iceberg 导入
- S3 Express One
- GCS 导入
- Cloudflare R2 导入
- 通过 HTTPS / S3 使用 DuckDB
- Fastly 对象存储导入
- 元查询
- ODBC
- 性能
- Python
- 安装
- 执行 SQL
- Jupyter Notebooks
- marimo Notebooks
- Pandas 上的 SQL
- 从 Pandas 导入
- 导出到 Pandas
- 从 Numpy 导入
- 导出到 Numpy
- Arrow 上的 SQL
- 从 Arrow 导入
- 导出到 Arrow
- Pandas 上的关系型 API
- 多个 Python 线程
- 与 Ibis 集成
- 与 Polars 集成
- 使用 fsspec 文件系统
- SQL 编辑器
- SQL 功能
- 代码片段
- 故障排除
- 术语表
- 离线浏览
- 操作手册
- 开发
- 内部结构
- 为什么选择 DuckDB
- 行为准则
- 发布日历
- 路线图
- 站点地图
- 在线演示
采样用于随机选择数据集的子集。
示例
使用 `reservoir
` 采样从 `tbl
` 中精确选择 5 行。
SELECT *
FROM tbl
USING SAMPLE 5;
使用 `system
` 采样,从表中选择大约 10% 的样本。
SELECT *
FROM tbl
USING SAMPLE 10%;
警告 默认情况下,当你指定一个百分比时,每个 向量 都将以该概率包含在样本中。如果你的表包含少于约 1 万行,建议使用
bernoulli
采样选项,它会独立地将概率应用于每一行。即使如此,你有时会得到多于或少于指定百分比的行数,但完全没有行的情况则不太可能发生。要精确获得 10% 的行(四舍五入后),你必须使用reservoir
采样选项。
使用 `bernoulli
` 采样,从表中选择大约 10% 的样本。
SELECT *
FROM tbl
USING SAMPLE 10 PERCENT (bernoulli);
使用 `reservoir
` 采样,从表中选择精确 10% 的样本(四舍五入后)。
SELECT *
FROM tbl
USING SAMPLE 10 PERCENT (reservoir);
使用固定种子(100)的 reservoir 采样,从表中选择精确 50 行的样本。
SELECT *
FROM tbl
USING SAMPLE reservoir(50 ROWS)
REPEATABLE (100);
使用固定种子(377)的 `system
` 采样,从表中选择大约 20% 的样本。
SELECT *
FROM tbl
USING SAMPLE 20% (system, 377);
在与 `tbl2
` 进行连接之前,选择 `tbl
` 中大约 20% 的样本。
SELECT *
FROM tbl TABLESAMPLE reservoir(20%), tbl2
WHERE tbl.i = tbl2.i;
在与 `tbl2
` 进行连接之后,选择 `tbl
` 中大约 20% 的样本。
SELECT *
FROM tbl, tbl2
WHERE tbl.i = tbl2.i
USING SAMPLE reservoir(20%);
语法
采样允许你随机提取数据集的子集。采样对于更快地探索数据集很有用,因为通常你可能对查询的精确答案不感兴趣,而只对数据的外观和内容的大致指示感兴趣。采样可以让你更快地获得查询的近似答案,因为它们减少了需要通过查询引擎的数据量。
DuckDB 支持三种不同的采样方法:`reservoir
`、`bernoulli
` 和 `system
`。默认情况下,当需要精确行数采样时,DuckDB 使用 `reservoir
` 采样;当指定百分比时,则使用 `system
` 采样。下面详细描述了这些采样方法。
采样需要一个样本大小,它表示将从总人口中采样的元素数量。采样可以以百分比(`10%
` 或 `10 PERCENT
`)或固定行数(`10
` 或 `10 ROWS
`)的形式给出。所有三种采样方法都支持按百分比采样,但只有 reservoir 采样支持采样固定数量的行。
采样是概率性的,也就是说,除非明确指定种子,否则不同运行之间的样本可能会有所不同。指定种子仅在未启用多线程(即 `SET threads = 1
`)的情况下保证样本相同。在多个线程对样本进行操作的情况下,即使使用固定种子,样本也未必一致。
reservoir
蓄水池采样是一种流式采样技术,它通过维护一个大小等于样本大小的蓄水池来选择随机样本,并随着更多元素的进入而随机替换元素。蓄水池采样允许我们精确指定在结果样本中想要的元素数量(通过选择蓄水池的大小)。因此,与 system 和 bernoulli 采样不同,蓄水池采样总是输出相同数量的元素。
蓄水池采样仅推荐用于小样本量,不建议与百分比一起使用。这是因为蓄水池采样需要具体化整个样本,并在具体化样本中随机替换元组。样本量越大,此过程带来的性能开销就越高。
当使用多进程时,蓄水池采样还会产生额外的性能开销,因为蓄水池需要在不同线程之间共享以确保无偏采样。当蓄水池非常小的时候,这不是一个大问题,但当样本量很大时,成本会很高。
最佳实践 如果可能,请避免在样本量大时使用蓄水池采样。蓄水池采样要求整个样本在内存中具体化。
bernoulli
伯努利采样只能在指定采样百分比时使用。它相当简单:基础表中的每一行都以等于指定百分比的概率包含在内。因此,即使指定相同的百分比,伯努利采样也可能返回不同数量的元组。预期行数等于表中指定百分比的行数,但会有一定的方差。
因为伯努利采样是完全独立的(没有共享状态),所以与多个线程一起使用伯努利采样不会有性能损失。
system
系统采样是伯努利采样的一种变体,但有一个关键区别:每个向量都以等于采样百分比的概率包含在内。这是一种聚类采样形式。系统采样比伯努利采样更高效,因为它无需执行每元组选择。
预期行数仍然等于表中指定百分比的行数,但方差高出 `vectorSize
` 倍。因此,系统采样不适用于行数少于约 1 万行的数据集,因为在这种情况下,即使你要求 `50 PERCENT
`,也可能发生所有行都被过滤掉,或者所有数据都被包含的情况。
表采样
从语法和效果上看,`TABLESAMPLE
` 和 `USING SAMPLE
` 子句是相同的,但有一个重要区别:tablesample 直接从它们所指定的表中采样,而 sample 子句则在整个 FROM 子句解析后进行采样。这在查询计划中存在连接时非常重要。
`TABLESAMPLE
` 子句本质上等同于使用 `USING SAMPLE
` 子句创建一个子查询,即以下两个查询是相同的
在连接之前,对 `tbl
` 进行 20% 的采样
SELECT *
FROM
tbl TABLESAMPLE reservoir(20%),
tbl2
WHERE tbl.i = tbl2.i;
在连接之前,对 `tbl
` 进行 20% 的采样
SELECT *
FROM
(SELECT * FROM tbl USING SAMPLE reservoir(20%)) tbl,
tbl2
WHERE tbl.i = tbl2.i;
在连接之后,对 20% 的数据进行采样(即,对连接结果的 20% 进行采样)
SELECT *
FROM tbl, tbl2
WHERE tbl.i = tbl2.i
USING SAMPLE reservoir(20%);