⌘+k ctrl+k
1.4 (LTS)
搜索快捷键 cmd + k | ctrl + k
非确定性行为

DuckDB 中的某些运算符表现出非确定性行为。最显著的是,SQL 使用集合语义,这允许以不同的顺序返回结果。DuckDB 利用这一点来提高性能,特别是在执行多线程查询时。其他因素,例如使用不同的编译器、操作系统和硬件架构,也可能导致顺序的变化。本页面记录了非确定性为“预期行为”的情况。如果您希望使查询具有确定性,请参阅“解决非确定性”部分

集合语义

非确定性的最常见来源之一是 SQL 使用的集合语义。例如,如果您重复运行以下查询,可能会得到两个不同的结果

SELECT *
FROM (
    SELECT 'A' AS x
    UNION
    SELECT 'B' AS x
);

结果 A, BB, A 都是正确的。

不同平台上的不同结果:array_distinct

array_distinct 函数在不同平台上可能会以不同的顺序返回结果

SELECT array_distinct(['A', 'A', 'B', NULL, NULL]) AS arr;

对于此查询,[A, B][B, A] 都是有效结果。

多线程环境下的浮点聚合操作

浮点数不精确性可能会在多线程配置中产生不同的结果:例如,stddevcorr 可能会产生非确定性的结果

CREATE TABLE tbl AS
    SELECT 'ABCDEFG'[floor(random() * 7 + 1)::INT] AS s, 3.7 AS x, i AS y
    FROM range(1, 1_000_000) r(i);

SELECT s, stddev(x) AS standard_deviation, corr(x, y) AS correlation
FROM tbl
GROUP BY s
ORDER BY s;

此查询预期的标准差和相关性对于所有 s 的值都应为 0。然而,当在多个线程上执行时,由于浮点数的不精确性,查询可能会返回极小的数字(0 <= z < 10e-16)。

解决非确定性

对于大多数用例,非确定性不会引起任何问题。但是,在某些情况下,我们需要确定性的结果。在这些情况下,请尝试以下解决方法:

  1. 限制线程数,以防止因多线程引入非确定性。

    SET threads = 1;
    
  2. 强制排序。例如,您可以使用 ORDER BY ALL 子句

    SELECT *
    FROM (
        SELECT 'A' AS x
        UNION
        SELECT 'B' AS x
    )
    ORDER BY ALL;
    

    您还可以使用 list_sort 对列表进行排序

    SELECT list_sort(array_distinct(['A', 'A', 'B', NULL, NULL])) AS i
    ORDER BY i;
    

    还可以引入确定性洗牌 (deterministic shuffling)

© 2025 DuckDB 基金会,阿姆斯特丹,荷兰
行为准则 商标使用指南