有没有一种方法可以在不硬编码0位比特串宽度的情况下进行非零比特串测试?
例如,假设我有两个表,用户和功能,每个表都有掩码,我想进行以下测试:
SELECT u.name FROM Users u, Features f
WHERE u.mask & f.mask;
匹配隐式的非零结果。但是,SQL要求对于WHERE
需要显式的布尔值结果,而不是像这样的隐式转换:
SELECT u.name FROM Users u, Features f
WHERE (u.mask & f.mask) != 0::BIT(2048);
我不想在此查询中硬编码2048
(或任何其他数字),原因有很多。
测试expr = 0
或expr > 0
会导致类型错误。奇怪的是,我可以测试expr = 0::BIT(1)
,但这会得到错误的答案,因为Postgres不认为所有全零的位串都相等。
select 0::BIT(2) > 0::BIT(1);
?column?
----------
t
(1 row)
我能通过以下方式创建一个计算出的零值:
我能通过以下方式创建一个计算出的零值:
SELECT u.name FROM Users u, Features f
WHERE (u.mask & f.mask) != (u.mask & ~u.mask);
这个方法虽然可行,但感觉像是一个糟糕的黑客攻击。
有什么建议或见解吗?
结果
我对下面提供的几个选项进行了基准测试。感谢您的建议,Erwin!
根据非常大的数据集和 100,000 个查询,我发现以下结构导致了每秒相关查询。希望 Postgres 团队中的某些人看到此问题并提供通用的 0 以加速事情的发展!不幸的是,大多数通用方法似乎会导致字符串转换,这是相当昂贵的。
Constructs | Queries / s
----------------------------------------+--------------
(u.mask & f.mask) <> 0::BIT(2048) | 158
(u.mask & f.mask) <> (u.mask # u.mask) | 135
(u.mask & f.mask) <> (u.mask & ~u.mask) | 125
position('1' IN (u.mask & f.mask)) > 0 | 37
(u.mask & f.mask)::TEXT !~ '^0+$' | 27
非零比特字符串测试
是什么?而你所说的匹配隐式非零结果
意味着什么?能否解释一下或者举一些例子说明哪些情况会通过测试,哪些情况则不会?你的列是否定义为NOT NULL
?请提供你的表定义(可以在 psql 中使用\d users
命令)。另外,请问你使用的是哪个版本的 Postgres? - Erwin Brandstetter