这是对我的查询的一个巨大的简化,但本质上我有一系列的公用表表达式,它们相互建立在一起,我想把它们转换成一个视图。问题是,当我尝试使用视图时,它非常慢,但当我运行查询时,它却非常快。
CREATE VIEW user_view AS
WITH cte AS(
SELECT first,middle,last FROM user
),
cte2 AS(
SELECT *,first + middle AS first_middle FROM cte
),
cte3 AS(
SELECT *,first_middle + last AS full_name FROM cte2
)
SELECT * from cte3;
快速查询
WITH cte AS(
SELECT first,middle,last FROM user WHERE user_id = 5
),
cte2 AS(
SELECT *,first + middle AS first_middle FROM cte
),
cte3 AS(
SELECT *,first_middle + last AS full_name FROM cte2
)
SELECT * from cte3;
使用视图减慢查询
SELECT * from user_view WHERE user_id = 5
发布于 2018-06-08 09:04:54
Postgres为CTE实现了一种叫做“优化栅栏”的东西。这意味着Postgres将每个CTE具体化以进行后续处理。一个很好的效果是CTE可以被多次引用,但代码只执行一次。缺点是,在实现CTE之后,诸如索引之类的便利被“遗忘”了。
对于你的问题,视图实际上是无关紧要的(没有双关语的意思)。在此版本中:
WITH cte AS (
SELECT first, middle, last FROM user WHERE user_id = 5
),
cte2 AS (
SELECT *, first || middle AS first_middle FROM cte
),
cte3 AS (
SELECT *, first_middle || last AS full_name FROM cte2
)
SELECT *
FROM cte3;
第一个CTE大概从表中拉出一条记录。据推测,它在id上使用了一个索引,甚至这个操作也非常快。这一条记录是其余CTE处理的唯一记录。
在此版本中:
WITH cte AS (
SELECT first, middle, last FROM user
),
cte2 AS (
SELECT *, first || middle AS first_middle FROM cte
),
cte3 AS (
SELECT *, first_middle || last AS full_name FROM cte2
)
SELECT *
FROM cte3
WHERE user_id = 5;
CTE正在处理user
表中的所有数据。最后,需要找到满足WHERE
条件的行。物化的CTE不再有索引。。。因此数据是按顺序搜索的。
此行为不适用于子查询,因此您可以尝试使用子查询而不是CTE重写逻辑。
Postgres以不同于其他数据库的方式优化CTE。例如,SQL Server从不具体化子查询;代码总是“插入”到查询中,并作为一个整体进行优化。事实上,SQL Server论坛有相反的顾虑--实现一个实现CTE的选项。与其他数据库不同。Oracle是一个似乎同时采用了这两种方法的数据库。
https://stackoverflow.com/questions/50751825
复制相似问题