2013-07-04 158 views
3

我知道这是一个常见问题,我已经阅读了其他几篇文章和论文,但是我找不到一个考虑索引字段和两个查询都可能返回的记录数量的问题。嵌套选择的性能

我的问题确实很简单。在这里推荐使用类似于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数据库中。

+1

。 。一般来说,没有指定数据库的性能问题是毫无意义的。 SQL是一种描述性语言,而不是过程语言,所以优化器(引擎的一部分)可以自由选择任何查询计划对于给定查询的最佳选择。 –

+0

@GordonLinoff好点。该数据库是一个Oracle数据库。这个语言应该不是很重要,我想只是用SQL语法来编写它。 – mixkat

+1

。 。根据Tom Kyte的说法,Oracle优化器足够智能,可以识别相关的子查询并将它们转换为适当的连接(http://asktom.oracle.com/pls/apex/f?p=100:11:0::NO :: P11_QUESTION_ID:3167884300346662300)。 Oracle有一个非常好的优化器。有趣的是,第一个版本在MySQL中性能完全可观。 。 。直到解决问题的版本5.6。 –

回答

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等) - 也是过滤的,所以 - 应该被索引。
  • 数据库引擎将自行选择最佳订单操作(或并行)。在大多数情况下,你不能确定这一点。
  • 使用Oracle EXPLAIN PLAN(类似于大多数数据库)来比较实际数据上不同查询的执行计划。
4

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

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

例如:

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); 

我不知道有关的大量数据的性能。