为什么 returns 表的函数比 运行 实际查询慢得多?
why functions that returns tables are so much slower then running the actual query?
我是 PostgreSQL 的新手,所以我想我遗漏了一些基本信息,我在谷歌搜索时没有找到的信息,我想我真的不知道正确的关键字,希望我会在这里获取丢失的信息:)
我正在使用 PostgreSQL 11.4。
我在创建一个 return 将查询结果作为 table 的函数时遇到了很多问题,它的执行速度比 运行 实际速度慢了大约 50 倍查询,有时甚至更多。
我明白IMMUTABLE
可以在没有table扫描时使用,只是当我根据函数参数操作和return数据和STABLE
时如果具有相同参数的查询执行 table 扫描并且总是 return 相同的结果。
所以我的函数创建格式是这样的:
CREATE FUNCTION fnc_name(columns...)
RETURNS TABLE ( columns..) STABLE AS $func$
BEGIN
select ...
END $func$ LANGUAGE pgplsql;
我无法在此处显示查询,因为它与工作相关,但仍然......关于创建函数,我不太明白为什么它这么慢?我需要完全理解这个问题,因为我需要创建更多的函数,现在看来我需要 运行 实际查询以获得适当的性能而不是使用函数,但我仍然没有真正的线索至于为什么!
如能提供有关此问题的任何信息,我们将不胜感激。
一切都取决于这个函数的用法,以及返回关系的大小。
首先我要说 - 不要写这些函数。它是已知的反模式。 我将尝试解释原因。请改用视图。
用高级 PL 语言(如 Perl、Python 或 PLpgSQL 编写的 table 函数的结果已具体化。当 table 较小时(至 work_mem
),它存储在内存中。更大的 tables 存储在临时文件中。它可能会有很大的开销。
函数是优化器的黑盒 - 无法下推谓词,没有正确的统计信息,无法使用连接形式或连接顺序。因此,由于不可能的优化,一些不重要的查询可能会变慢(一点点或显着)。
这些规则有一个例外 - 简单的 SQL 函数。 SQL 函数(具有单个 SQL 语句的函数)可以内联(当满足某些先决条件时)。由于内联函数的主体被合并到外部 SQL 查询的主体,结果与您直接编写子查询相同。所以结果没有具体化,也不是优化的障碍。
有一个基本规则 - 仅当无法通过 SQL 计算某些数据时才使用函数。不要试图隐藏 SQL 或封装 SQL (在其他地方 - 为了简化一些复杂的查询使用视图而不是函数)。相同的规则适用于所有 SQL 数据库(Oracle、DB2、MSSQL)。 Postgres 也不例外。
本说明不针对存储过程(函数)。这是一项伟大的技术。但它需要特定的编程风格。将查询包装到函数中(当没有任何其他函数时)是不好的。
我是 PostgreSQL 的新手,所以我想我遗漏了一些基本信息,我在谷歌搜索时没有找到的信息,我想我真的不知道正确的关键字,希望我会在这里获取丢失的信息:)
我正在使用 PostgreSQL 11.4。
我在创建一个 return 将查询结果作为 table 的函数时遇到了很多问题,它的执行速度比 运行 实际速度慢了大约 50 倍查询,有时甚至更多。
我明白IMMUTABLE
可以在没有table扫描时使用,只是当我根据函数参数操作和return数据和STABLE
时如果具有相同参数的查询执行 table 扫描并且总是 return 相同的结果。
所以我的函数创建格式是这样的:
CREATE FUNCTION fnc_name(columns...)
RETURNS TABLE ( columns..) STABLE AS $func$
BEGIN
select ...
END $func$ LANGUAGE pgplsql;
我无法在此处显示查询,因为它与工作相关,但仍然......关于创建函数,我不太明白为什么它这么慢?我需要完全理解这个问题,因为我需要创建更多的函数,现在看来我需要 运行 实际查询以获得适当的性能而不是使用函数,但我仍然没有真正的线索至于为什么!
如能提供有关此问题的任何信息,我们将不胜感激。
一切都取决于这个函数的用法,以及返回关系的大小。
首先我要说 - 不要写这些函数。它是已知的反模式。 我将尝试解释原因。请改用视图。
用高级 PL 语言(如 Perl、Python 或 PLpgSQL 编写的 table 函数的结果已具体化。当 table 较小时(至
work_mem
),它存储在内存中。更大的 tables 存储在临时文件中。它可能会有很大的开销。函数是优化器的黑盒 - 无法下推谓词,没有正确的统计信息,无法使用连接形式或连接顺序。因此,由于不可能的优化,一些不重要的查询可能会变慢(一点点或显着)。
这些规则有一个例外 - 简单的 SQL 函数。 SQL 函数(具有单个 SQL 语句的函数)可以内联(当满足某些先决条件时)。由于内联函数的主体被合并到外部 SQL 查询的主体,结果与您直接编写子查询相同。所以结果没有具体化,也不是优化的障碍。
有一个基本规则 - 仅当无法通过 SQL 计算某些数据时才使用函数。不要试图隐藏 SQL 或封装 SQL (在其他地方 - 为了简化一些复杂的查询使用视图而不是函数)。相同的规则适用于所有 SQL 数据库(Oracle、DB2、MSSQL)。 Postgres 也不例外。
本说明不针对存储过程(函数)。这是一项伟大的技术。但它需要特定的编程风格。将查询包装到函数中(当没有任何其他函数时)是不好的。