上下文
我正在构建一个Postgres扩展,它增加了使用语言变量进行模糊查询的可能性。例如:
SELECT age~=('age'|>'adult') FROM people;
将返回一个人是成人这一事实的合理性(成人定义为梯形函数30/40~60\65
。
问题
我做了一个函数,可以返回指定值和语言变量的语言名称:
SELECT age, age~>'age' FROM people;
返回
age | age~>'age'
-----+--------------
20 | young adult
10 | child
45 | adult
60 | old
此函数和运算符的来源如下:
CREATE FUNCTION get_fuzzy_name(
input FLOAT8,
type_name VARCHAR(64)
) RETURNS VARCHAR(64) AS $$
DECLARE
type_id fuzzy.types.id%TYPE;
deg FLOAT8;
result_name VARCHAR(64);
BEGIN
type_id := get_fuzzy_type(type_name); -- returns type's id based on it's name
SELECT
degree(input, fun) AS d, name
INTO
deg, result_name
FROM fuzzy.functions
WHERE type=type_id
ORDER BY d DESC LIMIT 1;
IF deg=0 THEN
RETURN NULL;
END IF;
RETURN result_name;
END;
$$ LANGUAGE plpgsql IMMUTABLE STRICT;
CREATE OPERATOR ~> (
PROCEDURE = get_fuzzy_name,
LEFTARG = FLOAT8,
RIGHTARG = VARCHAR(64)
);
问题在于,对于每行,上面的函数都会查询模糊类型,并一次又一次地起作用。因此,我提出了这一点,作为改进的基础(模糊函数保存在变量中):
CREATE TYPE FUZZY_TYPE_FUNCTION AS (
func TRAPEZOIDAL_FUNCTION,
range_name VARCHAR(64)
);
CREATE FUNCTION get_fuzzy_name(
input FLOAT8,
type_name VARCHAR(64)
) RETURNS VARCHAR(64) AS $$
DECLARE
f FUZZY_TYPE_FUNCTION;
_type_functions FUZZY_TYPE_FUNCTION[] := array(SELECT (fun, name) FROM fuzzy.functions WHERE fuzzy.functions.type=type_name);
_deg_tmp FLOAT8;
_deg FLOAT8;
_result_name VARCHAR(64);
BEGIN
_deg := 0;
FOREACH f IN array(_type_functions) LOOP
_deg_tmp := degree(input, f.func);
RAISE NOTICE '% && % = %', f, input, _deg_tmp;
IF _deg<_deg_tmp THEN
_deg := _deg_tmp;
_result_name := f.range_name;
EXIT WHEN _deg=1;
END IF;
END LOOP;
IF _deg=0 THEN
RETURN NULL;
END IF;
RETURN _result_name;
END;
$$ LANGUAGE plpgsql IMMUTABLE STRICT;
是否有一种方法可以使每个查询一次获取函数表的值并将其缓存,以便可以重用它并极大地加快整个查询的速度?
其他信息
根据要求,这些表是:
CREATE SCHEMA IF NOT EXISTS fuzzy;
CREATE TABLE IF NOT EXISTS fuzzy.types (
id SERIAL PRIMARY KEY,
name VARCHAR(64) UNIQUE
);
CREATE TABLE IF NOT EXISTS fuzzy.functions (
type INT NOT NULL,
fun TRAPEZOIDAL_FUNCTION NOT NULL,
name VARCHAR(64),
FOREIGN KEY (type) REFERENCES fuzzy.types (id) ON DELETE CASCADE,
UNIQUE (type, name)
);
fuzzy.types
可能会包含几行,这些行是id-name对,
fuzzy.functions
最有可能在每种类型中包含3到10行,对于重度用例,我可能会包含约500行。
答案 0 :(得分:1)
您可能会基于一些关于功能性能的误导性假设。
请尝试使用此简化的SQL函数:
CREATE FUNCTION get_fuzzy_name(_input FLOAT8, _type_name VARCHAR(64))
RETURNS VARCHAR(64) AS
$func$
SELECT f.name
FROM fuzzy.functions f
JOIN fuzzy.types t ON t.id = f.type
WHERE t.name = _type_name
AND degree(_input, f.fun) > 0
ORDER BY degree(_input, f.fun) DESC
LIMIT 1;
$func$ LANGUAGE sql STABLE;
LANGUAGE sql
。没有变量,赋值,IF
构造,... 1个简单查询。
完全重写,但应等效。
STABLE
,而不是IMMUTABLE
。
根本没有嵌套函数调用。替换为联接。应该便宜些。
但是,内联未公开的degree()
函数也可能更便宜。 May 甚至可以简化为更快的“最近邻居”查询。信息不足。
此函数可以内联,而不是原始函数。
我删除了STRICT
,可能是这样。无法判断,信息不足。
请参见Postgres Wiki about inlining of scalar functions。
并且:
相关: