嵌套选择的性能

时间:2013-07-04 19:51:57

标签: sql performance database-performance query-performance

我知道这是一个常见的问题,我已经阅读了其他一些帖子和论文,但我找不到一个考虑了索引字段和两个查询都可以返回的记录量。

我的问题很简单。这里建议使用类似SQL的语法编写两者中的哪一个(就性能而言)。

首先查询:

Select *
from someTable s
where s.someTable_id in
                    (Select someTable_id 
                     from otherTable o
                     where o.indexedField = 123)

第二次查询:

Select *
from someTable
where someTable_id in
                  (Select someTable_id 
                   from otherTable o
                   where o.someIndexedField = s.someIndexedField
                   and o.anotherIndexedField = 123)

我的理解是第二个查询将在数据库中查询外部查询将返回的每个元组,其中第一个查询将首先评估内部选择,然后将过滤器应用于外部查询。

现在,第二个查询可以查询数据库超快速,因为someIndexedField字段已编入索引但是说我们有数千或数百万条记录使用第一个查询会不会更快?

注意:在Oracle数据库中。

2 个答案:

答案 0 :(得分:4)

在MySQL中,如果嵌套选择在同一个表上,那么查询的执行时间可能就是地狱。

提高MySQL性能的一个好方法是为嵌套选择创建一个临时表,并对该表应用主选择。

例如:

Select *
from someTable s1
where s1.someTable_id in
                    (Select someTable_id 
                     from someTable s2
                     where s2.Field = 123);

可以通过以下方式获得更好的表现:

create temporary table 'temp_table' as (
  Select someTable_id 
  from someTable s2
  where s2.Field = 123
);

Select *
from someTable s1
where s1.someTable_id in
                    (Select someTable_id 
                     from tempTable s2);

我不确定大量数据的性能。

答案 1 :(得分:2)

关于第一个查询:

  

第一个查询将首先评估内部选择,然后应用   过滤到外部查询。

那不是那么简单。

在SQL中,大多数情况下无法告诉首先执行的内容以及稍后将执行的内容。

因为SQL - 声明性语言。

您的“嵌套选择” - 仅在视觉上,而非技术上。

示例1 - 在“someTable”中有10行,在“otherTable”中 - 10000行。

在大多数情况下,数据库优化器将首先读取“someTable”,然后检查otherTable是否匹配。为此,它可能会,也可能不会根据情况使用索引,在这种情况下填写 - 它将使用“indexedField”索引。

示例2 - 在“someTable”中,您有10000行,在“otherTable”中 - 10行。

在大多数情况下,数据库优化器将从内存中的“otherTable”读取所有行,过滤它们123,然后在someTable PK(someTable_id)索引中找到匹配项。结果 - “otherTable”中不会使用任何索引。

关于第二个查询:

与第一次完全不同。所以,我不知道如何比较它们:

  • 首先查询一对两个表:s.someTable_id = o.someTable_id
  • 第二个查询将两个表连接成两对:s.someTable_id = o.someTable_id AND o.someIndexedField = s.someIndexedField。

链接两个表的常用做法 - 是您的第一个查询。 但是,o.someTable_id应该编入索引。

如此常见的规则是:

  • 所有PK - 应编入索引(默认为索引)
  • 所有用于过滤的列(如在WHERE部分中使用的那样)都应编入索引
  • 用于提供表之间匹配的所有列(包括IN,JOIN等) - 也是过滤,因此 - 应该被编入索引。
  • DB Engine将自行选择最佳订单操作(或并行)。在大多数情况下,你无法确定这一点。
  • 使用Oracle EXPLAIN PLAN (类似于大多数数据库存在)来比较不同查询对实际数据的执​​行计划。