2014-03-25 37 views
6

如果我有一个非常大的表将这个查询加载在内存中的整个表它过滤的重置之前:这是否会查询加载整个表中存储

with parent as 
(
    select * from a101 
) 
select * from parent 
where value1 = 159 

正如你可以看到父查询参考整个桌子。这会加载到内存中吗?这是查询的一个非常简化的版本。真正的查询有几个连接到其他表。我正在评估sql server 2012和postgrsql。

+0

如果这对于SQL Server,postgres或两者兼而有之?如果只适用于postgres,请删除SQL Server标记 –

回答

5

在PostgreSQL(真为9.4,至少)CTEs act as optimisation fences

即使在微不足道的情况下,查询优化器也不会将CTE条件平铺到外部查询,下推限定符或拉取限定符。因此,CTE术语中的不合格SELECT将始终执行全表扫描(如果存在合适的索引,则只执行索引扫描)。

因此,在PostgreSQL里,这两样东西有很大的不同的确,作为一个简单的EXPLAIN会显示:

with parent as 
(
    select * from a101 
) 
select * from parent 
where value1 = 159 

SELECT * 
FROM 
(
    SELECT * FROM a101 
) AS parent 
WHERE value1 = 159; 

然而, “会扫描整个表” 没有按'必然意味着“将把整个表加载到内存中”。 PostgreSQL将使用一个TupleStore,当它变大时,它会透明地溢出到磁盘上的临时文件。

最初的理由是CTE术语中的DML是计划(并在后来实施的)。如果在CTE术语中有DML,则执行的可预测性和完整性至关重要。如果CTE调用数据修改功能,这也可能是真实的。

不幸的是,似乎没有人想到“......但如果它只是一个SELECT并且我们想要内联呢?”

社区中的许多人似乎将此视为功能,并定期将其作为解决优化程序问题的方法。我觉得这种态度完全令人困惑。因此,以后很难解决这个问题,因为人们有意使用CTE来阻止优化器改变查询。

换句话说,PostgreSQL滥用CTE作为伪查询提示(以及OFFSET 0黑客攻击),因为项目策略认为不需要或不支持真正的查询提示。

AFAIK MS SQL Server可以优化CTE障碍,但也可能选择实现结果集。

1

否。查询是作为一个整体进行评估的。如果您查看执行计划,您将看到过滤器谓词将应用于内部搜索。克服外部搜索的微不足道,我确信它会被优化。

检查执行计划 - 这是基准知识,你最好学习如何做到这一点。一旦你遇到了真正的性能问题,你将需要找出问题所在,这就是执行计划的来源。

+1

这对于PostgreSQL来说(不幸的是)在CTE的情况下是不正确的。 –

0

CTE只是使代码更具可读性的语言语法,它们对查询执行性能没有影响。

当执行查询时,它会根据预先定义的SQL Server查询执行阶段

1. FROM 
2. ON 
3. OUTER 
4. WHERE 
5. GROUP BY 
6. CUBE | ROLLUP 
7. HAVING 
8. SELECT 
9. DISTINCT 
10 ORDER BY 
11. TOP 

所以WHERE过滤器将被应用,然后再记录进行选择,从而完整的表不会获取执行在记忆中。

+0

这个订单是否有MS链接?谢谢 –

+0

在SQL Server的情况下,这是不正确的。例如,WHERE子句中的特定谓词可能会被推下到索引seek,这意味着您提出的顺序不正确。它按照查询计划告诉它的顺序执行任何操作。在极端情况下,它可能会根据where子句进行寻找,按顺序执行,然后分组,然后合并连接等。内存中的数据量是可用内存,高速缓存等的函数。如果没有任何自由物理内存,它们都不会被加载到内存中,它会转到页面文件,而不管查询。 –

+0

这在PostgreSQL中也是完全错误的。 –

2

我刚刚为此查询在PostgreSQL中制作了EXPLAIN。令人惊讶的是没有顺序扫描而不是索引查找:

CTE Scan on parent (cost=123.30..132.97 rows=2 width=1711) 
    Filter: (value1 = 159) 
    CTE parent 
    -> Seq Scan on a101 (cost=0.00..123.30 rows=430 width=2060) 

我有一个value1主键索引,它是用于简单select * from a101 where value1 = 159查询。

所以,答案是它会扫描整个表格。我很惊讶,我认为它可以作为一个视图或子查询,但事实并非如此。您可以用它来使用索引:

select * from (select * from a101) parent 
where value1 = 159` 
相关问题