【问题标题】:Index Results of Postgres Table FunctionPostgres表函数的索引结果
【发布时间】:2016-12-02 00:45:22
【问题描述】:

我正在寻找创建一个 Postgres 函数来缓存长时间运行的查询的结果,因此它只需要在每个事务中执行一次:

CREATE OR REPLACE FUNCTION get_records (
  _state VARCHAR(10)
)
RETURNS TABLE (
  id UUID
) AS
$$
DECLARE
  _temptable VARCHAR;
BEGIN
  _temptable := FORMAT('temp_state_%s', _state);

  IF NOT EXISTS(SELECT 1 FROM pg_tables WHERE tablename = _temptable) THEN
    EXECUTE FORMAT('CREATE TEMPORARY TABLE %I (id UUID NOT NULL, PRIMARY KEY(_uid)) ON COMMIT DROP', _temptable);
    EXECUTE FORMAT('INSERT INTO %I SELECT id FROM very_complex_nested_query', _temptable);
    EXECUTE FORMAT('ANALYZE %I', _temptable);
  END IF;

  RETURN QUERY EXECUTE FORMAT('SELECT id FROM %I', _temptable);
END;
$$
LANGUAGE 'plpgsql';

现在,我可以运行所有查询并加入此函数:

SELECT mt.*
FROM my_table1 mt
  INNER JOIN get_records('new') nr ON mt.id = nr.id
SELECT mt.*
FROM my_table2 mt
  INNER JOIN get_records('new') nr ON mt.id = nr.id
SELECT mt.*
FROM my_table3 mt
  INNER JOIN get_records('new') nr ON mt.id = nr.id
-- ... many more

我有一大堆这些,不保证哪个会先运行或按什么顺序运行。

这很好用,只是没有使用临时表上的主键索引。

如何从 Postgres 函数返回“表”,而不仅仅是查询的结果?

  1. 我正在使用函数来构建临时表而不是物化视图来解决“where clause doesn't get pushed into view that contains aggregation”问题。
  2. 我可以创建临时表,然后在所有查询中直接引用它,但这意味着必须构建某种阻塞机制以确保查询不会过早执行,而我正在使用的工具using 不能很好地支持这种机制。

【问题讨论】:

  • 不要创建临时表,不要使用临时表。不要分析临时表。将“very_complex_nested_query”放入一个普通的sql 函数中。使用 sql 函数的查询可以比 PL/pgSQL 呈现给优化器的黑盒更好地优化。
  • @a_horse_with_no_name 但是......“very_complex_nested_query”需要 5 分钟才能执行,并且由于我将结果加入到数百个单独的查询中,因此我将在总执行时间中增加天数。这不是临时表的确切用例吗? “普通 sql 函数”是什么意思?
  • 我的意思是language sq而不是language plpgsql——但是如果你想索引它,你需要在临时表上创建一个索引。
  • @a_horse_with_no_name 你如何创建一个动态命名的临时表并在同一个查询中使用纯 sql 加入它?我不能保证查询的顺序,所以临时表可能会在任何查询中创建,我不想多次创建它。我正在寻求实现“缓存未命中:工作、缓存和返回”的设计。
  • SQL 函数将包含 SELECT 语句,不包含临时表。您仍然以相同的方式使用它,但 Postgres 能够优化整个查询包括一个inside函数。像这样:dpaste.com/1J5REFJ

标签: postgresql


【解决方案1】:

您可以尝试使用修饰符STABLE,它表示

STABLE 表示该函数不能修改数据库,并且在单个表扫描中,对于相同的参数值,它将始终返回相同的结果,但其结果可能会在 SQL 语句中发生变化。

较新的 Postgres 版本也支持物化视图。您可以为连接创建物化视图。 AFAIK 物化视图也支持索引。

【讨论】:

  • 通过返回一个在 FROM 子句中使用的表,它不会只被扫描一次吗?在任何一种情况下,STABLE 和 IMMUTABLE 似乎都不会公开临时表的基础索引。至于物化视图,存在的问题是,如果您进行聚合,则无法从检查约束(例如分区表中)中受益,这会导致扫描所有分区(我的 5 分钟查询变为 18 -hour query) - 当我看到一个万行查询计划时,这让我很惊讶!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-02-17
  • 2014-01-31
  • 1970-01-01
  • 2014-01-29
  • 2011-06-11
  • 1970-01-01
  • 2015-02-17
相关资源
最近更新 更多