• 如果函数被声明为RETURNS SETOF RECORD且没有OUT参数,则函数体查询结果的类型,必须与调用方提供的列定义列表匹配
请注意,这些条件允许函数体是一个复杂的查询 , 甚至带有 CTE 表达式(但不包括递归 CTE)的查询 。这使得可内联的 SQL 函数比视图更加强大,因为它们可以以视图无法做到的方式获取参数,同时保留了视图的许多优点 。
示例让我们开始设置一个小的测试用例:
CREATE TABLE t (id integer, str text);INSERT INTO t (id, str)SELECT i, 'xxx'FROM generate_series(1, 10000) AS s(i);
下面是一个可由优化器内联的函数示例:
CREATE OR REPLACE FUNCTION ld(int)RETURNS numeric AS $$SELECT log(2, $1);$$ LANGUAGE 'sql' IMMUTABLE;
这是一个标记为IMMUTABLE的普通 SQL 函数 。它是可以被优化器进行优化的 。为了简单起见,该函数所做的只是计算一个对数:
SELECT ld(1024);ld--------------------- 10.0000000000000000(1 row)
如您所见,该函数工作符合预期 。
为了演示事情是如何运作的,我们在函数上创建了一个索引:
CREATE INDEX idx_ld ON t (ld(id));
正如预期的那样,该索引会像任何其他索引一样被使用 。但是 , 让我们来仔细看看索引条件:
EXPLAIN SELECT * FROM t WHERE ld(id) = 10;QUERY PLAN------------------------------------------------------------------------ Bitmap Heap Scan on t(cost=4.67..30.55 rows=50 width=8)Recheck Cond: (log('2'::numeric, (id)::numeric) = '10'::numeric)->Bitmap Index Scan on idx_ld(cost=0.00..4.66 rows=50 width=0)Index Cond: (log('2'::numeric, (id)::numeric) = '10'::numeric)(4 rows)ANALYZE t;EXPLAIN SELECT * FROM t WHERE ld(id) = 10;QUERY PLAN------------------------------------------------------------------ Index Scan using idx_ld on t(cost=0.29..8.30 rows=1 width=8)Index Cond: (log('2'::numeric, (id)::numeric) = '10'::numeric)(2 rows)
这里重要的观察结果是 , 索引条件实际上查找的是 log 函数而不是 ld 函数 。优化器已完全消除了函数调用 。还值得一提的是,更新的优化器统计信息对于生成有效的计划非常重要 。
逻辑上讲,这为以下查询打开了优化的大门:
EXPLAIN SELECT * FROM t WHERE log(2, id) = 10;QUERY PLAN------------------------------------------------------------------ Index Scan using idx_ld on t(cost=0.29..8.30 rows=1 width=8)Index Cond: (log('2'::numeric, (id)::numeric) = '10'::numeric)(2 rows)
优化器设法内联了该函数 , 并为我们提供了一个索引扫描,这远远优于高开销的顺序操作 。
推荐阅读
- 笑麻了!原来他们居然是亲生父子!我不会是最后一个知道的吧?
- 韩国歌手家试图自杀,遗书内容曝光,原来她一直过着这样悲惨生活
- 如何正确选择NoSQL数据库
- MySQL 核心模块揭秘,你看明白了吗?
- 查尔斯与戴安娜亲姐姐约会照曝光,原来当年戴安娜才是“备胎”!
- 《小日子》:以为周鱼是优质富二代,追求顾茉莉,结果原来是利用
- 原来她早已离世!33岁拒绝化疗后病逝,父母的坚守令人泪目
- 闹大了!明星为校园霸凌发声,原来大家经历过,评论区炸了
- 从 MySQL 到 ByteHouse,抖音精准推荐存储架构重构解读
- 34岁王子文恢复单身后的魔法穿搭,原来衬衫这么穿,也很时尚洋气