这是对我的查询的极大简化,但基本上我有一系列公共表表达式,它们相互构建,我想将它们转换为视图。问题是当我尝试使用视图时它非常慢,但当我运行查询时非常快。
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;
Run Code Online (Sandbox Code Playgroud)
快速查询
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;
Run Code Online (Sandbox Code Playgroud)
使用视图慢查询
SELECT * from user_view WHERE user_id = 5
Run Code Online (Sandbox Code Playgroud)
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;
Run Code Online (Sandbox Code Playgroud)
第一个 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;
Run Code Online (Sandbox Code Playgroud)
CTE 正在处理表中的所有数据user。最后,WHERE需要找到满足条件的行。物化的 CTE 不再有索引。. . 所以数据是按顺序搜索的。
此行为不会不适用于子查询,所以你可以尝试重写使用子查询,而不是热膨胀系数你的逻辑。
Postgres 优化 CTE 的方式与其他数据库不同。例如,SQL Server从不具体化子查询;代码总是“插入”到查询中并作为一个整体进行优化。事实上,SQL Server 论坛有相反的关注——实现一个选项来实现 CTE。与其他数据库不同。Oracle 是一种似乎同时采用两种方法的数据库。
| 归档时间: |
|
| 查看次数: |
289 次 |
| 最近记录: |