这是我的查询的一个巨大的简化,但基本上我有一系列常见的表表达式,彼此构建,我想转变为一个视图。问题是当我尝试使用视图时速度非常慢,但在运行查询时速度非常快。
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
答案 0 :(得分:3)
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是一个似乎采用这两种方法的数据库。