我需要创建一个Postgres 9.1 PL / pgSQL存储过程,该过程除了其他参数之外,还采用一系列值直接引用我的一个数据库列中的值。据我所知,在Postgres中执行此操作的规范方法是array。
当然,这是一项相当基本的任务。我的问题是可伸缩性:我的代码基本上可以正常工作,但是一旦传入的序列变得很大(如数百或数千个值),性能就会很差:
我的存储过程中使用
形式的数组中的相当简单的SELECT语句SELECT <some columns>
FROM <some tables>
WHERE <some other select criteria>
AND <column with values selected by array parameter>
IN (SELECT * FROM unnest(<array parameter>))
即使数据库不是很大而且数组中只有几十个值,需要几秒钟才能执行。
我的第一个怀疑是unnest(...)
是问题所在,但是只选择带有数组参数中引用的列的表非常快:
SELECT <some columns>
FROM <table with column ref'd in array parameter>
WHERE <column with values selected by array parameter>
IN (SELECT * FROM unnest(<array parameter>))
只需几毫秒。
我的问题:
答案 0 :(得分:2)
如何让我的查询表现更好?
如果您重写查询,我希望性能更快
SELECT <some columns>
FROM <some tables>
WHERE <some other select criteria>
AND <column with values selected by array parameter>
IN (SELECT * FROM unnest(<array parameter>));
为:
SELECT <some columns>
FROM (SELECT unnest(<array parameter>) AS param) x
JOIN <filtered table> ON <filter column> = x.param
JOIN <other table> ON <join criteria>
WHERE <some other select criteria>;
听起来,查询计划程序选择了一个次优计划,与IN子句相比,错误判断了其他WHERE
条件的成本。通过将其转换为显式JOIN
子句,您应该获得更好的查询计划。
通常,JOIN
s往往比PostgreSQL中的大IN
子句更快。
是否有使用数组作为参数的替代方法?
是。
您可以创建临时表,填充它并运行加入它的查询。
CREATE TEMP TABLE x(id int);
INSERT INTO x VALUES
(1), (2), (17), (18);
SELECT <some columns>
FROM x
JOIN <filtered table> ON <filter column> = x.id
JOIN <other table> ON <join criteria>
WHERE <some other select criteria>;
或者,更快,使用CTE用于相同的目的:
WITH x(id) AS (
VALUES (1::int), (2), (17), (18) -- type-cast on first element is enough
)
SELECT <some columns>
FROM x
JOIN <filtered table> ON <filter column> = x.id
JOIN <other table> ON <join criteria>
WHERE <some other select criteria>;
只要你想使用一个函数,一个数组参数,unnested inside也是我的选择。您也可以在函数内部的最后一个示例中使用CTE,只需使用unexst(arr)而不是VALUES子句。