使用 array_position() 函数从 pg_stats 获取列最常见的值

zer*_*dge 4 postgresql performance datatypes array postgresql-performance

我正在尝试执行这个简单的查询,以检查某个值(1000)是否属于 Postgres 查询优化器使用的 MCV 列表:

SELECT array_position(most_common_vals, 1000) 
FROM pg_stats 
WHERE tablename = 'tenk1' 
AND attname = 'unique1';
Run Code Online (Sandbox Code Playgroud)

但收到以下错误消息:

ERROR:  function array_position(anyarray, integer) does not exist
Run Code Online (Sandbox Code Playgroud)

如何解决?

array_position()是此处描述的标准函数,以下语句按预期返回2

SELECT array_position('{1,2,3}', 2);
Run Code Online (Sandbox Code Playgroud)

Erw*_*ter 5

解决方案

假设您的列的数据类型tenk1.unique1integer

SELECT array_position(most_common_vals::text::int[], 1000) 
FROM   pg_stats 
WHERE  tablename = 'tenk1' 
AND    attname = 'unique1';
Run Code Online (Sandbox Code Playgroud)

使用您的实际列类型和相应的数组类型。
您将获取位置,如果该值不在 MCV 列表中,则获取 NULL。

解决方案很短 - 不像......

解释

该函数array_position()被定义为采取(anyarray, anyelement)(或(anyarray, anyelement, integer)第二个变体)。

该列pg_stats.most_common_vals具有多态数据类型,anyarray能够保存任何数据类型的数组 - 原因显而易见。

anyarrayanyelement不允许作为用户创建表的数据类型。对于用户来说,两者都是多态伪类型。(但是 Postgres 可以在系统表中使用它们。)

同一函数中的多个多态变量必须解析为相同(或相应)的数据类型。手册:

此外,如果有位置声明anyarray和其他位置声明anyelement,则位置中的实际数组类型anyarray必须是其元素与任意元素位置中出现的类型相同的数组。

和:

因此,当使用多态类型声明多个参数位置时,最终效果是只允许实际参数类型的某些组合

大胆强调我的。

您发现了一个极端情况,其中多态与第二位置的- 或任何非多态类型的组合的函数类型解析失败。anyarrayinteger

1000在你的表达式中array_position(most_common_vals, 1000)是一个解析为 的数字常量integer。这些都会以类似的方式失败:

array_position(most_common_vals, '1000')  -- untyped string literal
Run Code Online (Sandbox Code Playgroud)
ERROR:  function array_position(anyarray, unknown) does not exist
Run Code Online (Sandbox Code Playgroud)
array_position(most_common_vals, '1000'::text)
Run Code Online (Sandbox Code Playgroud)
ERROR:  function array_position(anyarray, text) does not exist
Run Code Online (Sandbox Code Playgroud)

此外,没有为 定义强制转换anyarray,它是用户空间中的伪类型:

SELECT * FROM pg_cast WHERE castsource = 'anyarray'::regtype;  -- nothing found
Run Code Online (Sandbox Code Playgroud)

解决方法是将 totext作为垫脚石,因为任何类型都可以转换为text。然后投射到integer[],得到上面的解。

最后,我认为这是函数类型解析中的一个缺点,可以解决(很容易?)。但由于数据类型anyarray不应该在用户域中这样使用,我怀疑任何开发人员都会花时间在它上面......