与没有函数包装器的查询相比,SQL函数非常慢 [英] SQL function very slow compared to query without function wrapper

查看:101
本文介绍了与没有函数包装器的查询相比,SQL函数非常慢的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这个运行速度非常快(〜12ms)的PostgreSQL 9.4查询:

  SELECT 
auth_web_events.id ,
auth_web_events.time_stamp,
auth_web_events.description,
auth_web_events.origin,
auth_user.email,
customers.name,
auth_web_events.client_ip
FROM
public.auth_web_events,
public.auth_user,
public.customers
WHERE
auth_web_events.user_id_fk = auth_user.id AND
auth_user.customer_id_fk = customers.id AND
auth_web_events.user_id_fk = 2
ORDER BY
auth_web_events.id DESC;

但是,如果我将它嵌入到函数中,查询在所有数据中运行速度非常缓慢,通过每条记录运行,我缺少什么?,我有大约1M的数据,我想简化我的数据库层,将大型查询存储到函数和视图中。



<$ p $ (
id int,
time_stamp带时区的时间戳,
描述文本,
原始文本,
描述文本,
描述文本,
原始文本,
userlogin text,
customer text,
client_ip inet
)AS
$ func $
SELECT
auth_web_events.id,
auth_web_events.time_stamp,
auth_web_events.description,
auth_web_events.origin,
auth_user.email作为用户,
customers.name AS客户,
auth_web_events.client_ip
FROM
public.auth_web_events,
public.auth_user,
public.customers
WHERE
auth_web_events.user_id_fk = auth_user.id AND
auth_user.customer_id_fk = customers.id AND
auth_web_events.user_id_fk = $ 1
ORDER BY
auth_web_events.id DESC;
$ func $ LANGUAGE SQL;

查询计划为:

<$ p $ code>Sort(cost = 20.94..20.94 rows = 1 width = 791)(actual time = 61.905..61.906 rows = 2 loops = 1)
Sort Key:auth_web_events。 ID
排序方法:quicksort内存:25kB
- >嵌套循环(cost = 0.85..20.93 rows = 1 width = 791)(实际时间= 61.884..61.893 rows = 2循环= 1)
- >嵌套循环(cost = 0.71..12.75 rows = 1 width = 577)(实际时间= 61.874..61.879 rows = 2 loops = 1)
- >在auth_web_events(cost = 0.57..4.58 rows = 1 width = 61)(实际时间= 61.860..61.860 rows = 2 loops = 1) 2)
- >在auth_user上使用auth_user_pkey进行索引扫描(cost = 0.14..8.16 rows = 1 width = 524)(实际时间= 0.005..0.005 rows = 1 loops = 2)
Index Cond:(id = 2)
- >使用客户的customers_id_idx进行索引扫描(成本= 0.14..8.16行= 1宽度= 222)(实际时间= 0.004..0.005行= 1个循环= 2)
索引条件:(id = auth_user.customer_id_fk)
计划时间:0.369 ms
执行时间: 61.965 ms

我这样调用funcion:

  SELECT * from get_web_events_by_userid(2)



<

 函数扫描get_web_events_by_userid(cost = 0.25..10.25 rows = 1000 width = 172)(实际时间= 279107.142..279107.144行= 2个循环= 1)
计划时间:0.038 ms
执行时间:279107.175 ms

编辑:我只是更改参数,并且问题仍然存在。

EDIT2:Erwin答案的查询计划: $>

 Sort(cost = 20.94..20.94 rows = 1 width = 791)(actual time = 0.048..0.049 rows = 2 loops = 1)
排序键:w.id
排序方式:quicksort内存:25kB
- >嵌套循环(成本= 0.85..20.93行= 1宽度= 791)(实际时间= 0.030..0.037行= 2个循环= 1)
- >嵌套循环(成本= 0.71..12.75行= 1宽度= 577)(实际时间= 0.023..0.025行= 2个循环= 1)
- >使用auth_user_pkey在auth_user u上进行索引扫描(cost = 0.14..8.16 rows = 1 width = 524)(actual time = 0.011..0,012 rows = 1 loops = 1)
Index Cond:(id = 2)
- >索引条件:(user_id_fk = 2)在auth_web_events上使用auth_web_events_fk1进行索引扫描w(cost = 0.57..4.58 rows = 1 width = 61)(actual time = 0.008..0.008 rows = 2 loops = 1)

- >索引扫描使用customers_id_idx对客户c(成本= 0.14..8.16行= 1宽度= 222)(实际时间= 0.003..0.004行= 1个循环= 2)
索引条件:(id = u。 customer_id_fk)
计划时间:0.541 ms
执行时间:0.101 ms


解决方案

user

在重写你的函数时,我意识到你在这里添加了列别名:

pre $ SELECT
。 ..
auth_user.email AS用户
customers.name AS客户,


$ b $因为这些别名在函数外面是不可见的,并且在函数内部没有被引用,所以它们将被忽略。为了文档的目的,更好地使用a

但它也会使您的查询无效,因为 user 完全是 保留字 ,除非双引号,否则不能用作列别名。



奇怪的是,在我的测试中,该函数似乎与无效的别名一起工作。可能因为它被忽略(?)。但是我不确定这是否会产生副作用。



您的函数被重写(否则等效):

<$
RETURNS TABLE(
id int
,time_stamp timestamptz
,description text
,原始文本
,userlogin文本
,客户文本
,client_ip inet
)AS
$ func $
SELECT w.id
,w .time_stamp
,w.description
,w.origin
,u.email - AS用户 - 请发表评论!
,c.name - AS客户
,w.client_ip
FROM public.auth_user u
JOIN public.auth_web_events w ON w.user_id_fk = u.id
JOIN public.customers c ON c.id = u.customer_id_fk
WHERE u.id = $ 1 - 在这里恢复逻辑
ORDER BY w.id DESC
$ func $ LANGUAGE sql STABLE;

显然, STABLE 关键字改变了结果。 函数波动性 不应该是你描述的测试情况中的一个问题。该设置通常不会使单个孤立的函数调用获利。请阅读手册中的详细信息。此外,标准 EXPLAIN 不会显示关于 内部 函数内容的查询计划。您可以为此添加额外的 auto-explain 模块:



查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆