4

我无法理解查询计划缓存如何用于 pl/pgsql。

我想用JOINs 和IFs 构建多合一查询,因此我将有多个不同的查询参数,并且我将在多个表中进行搜索。

起初我以为使用pl/pgsql会为每个参数组合产生不同的计划,事实并非如此,因为我有不止一个表

直接出现在 PL/pgSQL 函数中的 SQL 命令必须在每次执行时引用相同的表和列;也就是说,您不能将参数用作 SQL 命令中的表或列的名称。为了绕过这个限制,您可以使用 PL/pgSQL EXECUTE 语句构造动态命令——代价是执行新的解析分析并在每次执行时构造一个新的执行计划。 从这里

我猜每次执行新的分析都会减慢速度。如果我不使用EXECUTEthen

如果语句没有参数,或者执行了很多次,SPI 管理器将考虑创建一个不依赖于特定参数值的通用计划,并将其缓存以供重复使用。通常,只有当执行计划对其中引用的 PL/pgSQL 变量的值不是很敏感时,才会发生这种情况。如果是这样,那么每次制定计划都是一种净赢。从这里

那我应该使用通用计划吗?是更快,还是因为每次都没有计划而变慢?至少它们被缓存了。我的查询对它们的变量很敏感,因为它们是动态的,但是什么

如果是这样,那么每次制定计划都是一种净赢。

实际上是什么意思?EXECUTE每次使用/plan 比通用的好还是坏?“净赢”让我感到困惑。

如果一个通用计划不准确并且EXECUTE/planning 每次都比较慢,那么为什么还要使用 pl/pgsql 呢?然后我可以用几个 if 编写一个简单的查询。

底线是,我无法断定在速度和计划缓存方面EXECUTE/plan each time是更好还是最差generic cached plan。请解释和建议,我很困惑。

作为参考,这就是我正在创建的。像现在一样工作,但将添加更多的 IFmytablesmywhere

DROP FUNCTION IF EXISTS __aa(ii int, fk int);
CREATE  FUNCTION __aa(ii int, fk int) RETURNS TABLE(id INTEGER,val text, fd integer) AS $$
DECLARE 
myt text;
mytables text;
mywhere text;
BEGIN

mytables := 'dyn_tab2';
mywhere := 'dyn_tab2.id=$1';
IF fk IS NOT NULL
THEN
mywhere := mywhere || 'AND dyn_tab2.fk_id=$2';
END IF;

RETURN QUERY EXECUTE format('
SELECT dyn_tab2.id, dyn_tab2.value, dyn_tab2.fk_id 
FROM %I WHERE ' ||mywhere,
mytables) 
USING ii, fk;

END;
$$
LANGUAGE 'plpgsql';

谢谢

4

1 回答 1

12

Plans for static queries (without EXECUTE) are always cached, plans for dynamic queries (with EXECUTE) cannot be cached.

In your case, it would be impossible to use a static query anyway, because, as you quote, that would mean that you can only use a fixed set of tables in your query.

I gather that you are confused by the discussion of the trade-offs between static and dynamic queries in the documentation.

Definition: query parameters are values that are not part of the query string, like $1 or a PL/pgSQL variable name in a static query.

For a static query, the procedure is as follows:

For the first 5 executions, it will be planned using the actual parameter values (“custom plan”), and if the estimated execution time is not significantly shorter than that of a plan that ignores the actual parameter values (“generic plan”), the generic plan will be used from the sixth execution on.

Since the generic plan is cached, that means that there is no planning cost from the sixth execution on.

Dynamic queries are planned every time they are executed.

The trade-off is the following: dynamic queries run up planning cost whenever they are executed, but since they are always planned with the actual parameter values, they end up with a better execution plan, which can save time during query execution.

Now if a query is sensitive to parameter values, that means that the optimal plan will vary significantly with the parameter values, so you will usually win if you plan the query every time.

Queries without parameters will always profit from plan caching, unless the table contents change a lot during the lifetime of a single session, so that the cached plan becomes suboptimal.

于 2018-01-16T08:33:06.703 回答