此查询是否会将整个表加载到内存中

时间:2014-03-25 05:28:15

标签: sql sql-server postgresql

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

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

如您所见,父查询引用整个表。这会加载到内存中。这是查询的一个非常简化的版本。真正的查询与其他表有一些连接。我正在评估sql server 2012和postgrsql。

4 个答案:

答案 0 :(得分: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;

但是,"会扫描整个表格"并不一定意味着"将整个表加载到内存中#34;。 PostgreSQL将使用TupleStore,当它变大时,它将透明地溢出到磁盘上的临时文件。

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

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

社区中的许多人似乎将此视为功能,并定期将其作为优化问题的解决方案发布。我觉得这种态度完全令人困惑。因此,以后很难解决此问题,因为人们在想要阻止优化器更改查询时故意使用CTE。

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

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

答案 1 :(得分: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`

答案 2 :(得分:1)

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

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

答案 3 :(得分: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过滤器然后选择记录,这样就不会在内存中提取完整的表。