我的问题与SQL order of operations类似,但有一点点扭曲,所以我认为这是公平的。
我正在使用Teradata。我有2个表:table1
,table2
。
table1
只有id
列
table2
包含以下列:id
,val
我可能错了,但我认为这两个陈述会产生相同的结果。
声明1。
SELECT table1.id, table2.val
FROM table1
INNER JOIN table2
ON table1.id = table2.id
WHERE table2.val<100
声明2。
SELECT table1.id, table3.val
FROM table1
INNER JOIN (
SELECT *
FROM table2
WHERE val<100
) table3
ON table1.id=table3.id
我的问题是,查询优化器是否足够智能 - 首先执行WHERE子句,然后在语句1中执行JOIN - 知道声明2中实际上不需要表3
我对SQL很陌生,所以如果我误解了什么,请教育我。
答案 0 :(得分:5)
这将取决于许多事情(表大小,索引,密钥分发等),您应该只检查执行计划:
你没有说哪个数据库,但这里有一些方法:
MySql EXPLAIN
SQL Server SET SHOWPLAN_ALL (Transact-SQL)
Oracle EXPLAIN PLAN
what is explain in teradata?
Teradata Capture and compare plans faster with Visual Explain and XML plan logging
答案 1 :(得分:4)
根据相关表的统计信息和索引的可用性,优化程序中的查询重写机制可能会或可能不会选择扫描Table2
以查找扫描前val < 100
的记录Table1
}。
在某些情况下,基于数据人口统计信息,联接,索引和统计信息,您可能会发现优化程序在您认为应该删除查询计划中的记录时。即使您有一个派生表,例如示例中的派生表。您可以通过简单地在派生表中放置GROUP BY来强制优化器处理派生表。然后,优化器必须先解析GROUP BY聚合,然后才能考虑解析示例中两个表之间的连接。
SELECT table1.id, table3.val
FROM table1
INNER JOIN (
SELECT table2.id, tabl2.val
FROM table2
WHERE val<100
GROUP BY 1,2
) table3
ON table1.id=table3.id
这并不是说您的标准方法应该是通过代码来运行。这通常是我最后一次度假,当我有一个查询计划时,它不会在计划中更早地消除无关的记录,并导致过多的数据被扫描并通过各种SPOOL文件传播。这只是一种技术,当您遇到这种情况时,可以将其放入工具箱中。
查询重写机制不断从一个版本更新到下一个版本,有关其工作原理的详细信息可以在Teradata 13.0的SQL Transaction Processing Manual中找到。
答案 2 :(得分:0)
除非我遗漏了什么,为什么你甚至需要Table1?
只需查询Table2
Select id, val
From table2
WHERE val<100
或者您使用table1中的行作为过滤器?也就是说,table1是否只保留表2中Ids的一个子集?
如果是这样,那么这也会起作用......
Select id, val
From table2
Where val<100
And id In (Select id
From table1)
但是要回答你的问题,是的,查询优化器应该足够智能,以确定执行将逻辑指令转换为物理结果所需步骤的最佳顺序。它使用数据库在每个表上维护的strored统计信息来确定要执行的操作(例如,使用什么类型的连接逻辑),以及执行操作的顺序,以便最大限度地减少磁盘IO和处理成本。< / p>
答案 3 :(得分:0)
Q1。首先执行WHERE子句,然后在语句1
中稍后加入问题是,如果你切换内部连接的顺序,即table2 INNER JOIN table1,那么我猜想在准备阶段,JOIN操作之前可以处理WHERE子句。但是,我猜即使您不更改原始查询,优化器也应该能够切换它们的顺序,如果它认为连接操作在获取整行时过于昂贵,那么它将首先应用WHERE。只是我的猜测。
Q2。知道声明2中实际上不需要表3
Teradata将以必要的方式解释您的第二个查询,因此它将继续处理表3的操作。