⌘+k ctrl+k
1.3 (稳定版)
搜索快捷键 cmd + k | ctrl + k
示例

采样用于随机选择数据集的子集。

示例

使用 `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%);