IN子句的SELECT DISTINCT或SELECT效率

时间:2016-02-23 15:13:08

标签: sql oracle

使用Oracle(如果重要)。这两个Select语句都会产生相同的最终结果,但哪一个更快?

SELECT * FROM tbl_A WHERE val IN (SELECT myField FROM tbl_B WHERE ... );

或者子查询中的SELECT DISTINCT会更好吗?

SELECT * FROM tbl_A WHERE val IN (SELECT DISTINCT myField FROM tbl_B WHERE ... );

谢谢!

2 个答案:

答案 0 :(得分:1)

不需要DISTINCT,一般来说,将DISTINCT添加到SELECT语句会增加SQL Server的工作量。

查看两者的查询计划。当你执行DISTINCT选项时,你会得到一个额外的SORT节点吗?

答案 1 :(得分:1)

SELECT * FROM account_item WHERE instrument_id IN (SELECT instrument_id FROM instrument WHERE market_id=202)

SELECT * FROM account_item WHERE instrument_id IN (SELECT distinct instrument_id FROM instrument WHERE market_id=202)

不同之处没有区别(正如您可能猜到的那样),两者都给出了这个执行计划:

ALL_ROWS    SELECT STATEMENT   Cost = 703
1.1     HASH JOIN
2.1       INDEX FAST FULL SCAN PRF_INSTRUMENT_COMPANY
2.2       TABLE ACCESS FULL ACCOUNT_ITEM

有什么不同之处:

1)子选择的基数

SELECT * FROM account_item WHERE instrument_id IN (SELECT instrument_id FROM     instrument WHERE symbol='MSFT')

ALL_ROWS    SELECT STATEMENT   Cost = 129
1.1     HASH JOIN
2.1       TABLE ACCESS BY INDEX ROWID INSTRUMENT
3.1         INDEX RANGE SCAN PRF_INSTRUMENT_MATCH
2.2       TABLE ACCESS FULL ACCOUNT_ITEM

2)你是否可以访问未编入索引的tbl_A列(又名select * hurts)

SELECT account_id FROM account_item WHERE instrument_id IN (SELECT distinct instrument_id FROM instrument WHERE market_id=202)

ALL_ROWS    SELECT STATEMENT   Cost = 608
1.1     HASH JOIN
2.1       INDEX FAST FULL SCAN PRF_INSTRUMENT_COMPANY
2.2       INDEX FAST FULL SCAN PRF_ACCOUNT_ITEM

3)一旦你有了良好的基数并访问了正在使用的索引中的列:

SELECT account_id FROM account_item WHERE instrument_id IN (SELECT instrument_id FROM instrument WHERE symbol='MSFT')

ALL_ROWS    SELECT STATEMENT   Cost = 33
1.1     HASH JOIN
2.1       TABLE ACCESS BY INDEX ROWID INSTRUMENT
3.1         INDEX RANGE SCAN PRF_INSTRUMENT_MATCH
2.2       INDEX FAST FULL SCAN PRF_ACCOUNT_ITEM

您的查询可以使用连接而不是子选择进行重写。

select a.account_id
from   account_item a,
       instrument i
where a.instrument_id=i.instrument_id
and i.symbol='MSFT'

ALL_ROWS    SELECT STATEMENT   Cost = 33
1.1     HASH JOIN
2.1       TABLE ACCESS BY INDEX ROWID INSTRUMENT
3.1         INDEX RANGE SCAN PRF_INSTRUMENT_MATCH
2.2       INDEX FAST FULL SCAN PRF_ACCOUNT_ITEM

使用示例表:

select a.* 
from tbl_A,tbl_B
where a.val=b.myField
and b...some other condition

subselect与join的效率可以引发新的争论。 Oracle被广告,以便它可以将... subselect转换为连接,正如您所看到的,执行计划是相同的。然而情况并非总是这样,取决于您是否访问tbl_a(帐户项目)的未编入索引字段,或者tbl_b(工具)标准的基数,事情可能会非常奇怪。

基本上,经验法则是:

  • 在标准必须已编入索引的情况下使用的每个列,优选地不是单独的,而是作为一组列覆盖在标准中使用的所有列,例如在工具上创建索引prf_fastInstruments(market_id,symbol)
  • 如果您有可能使索引唯一,请将其设为唯一
  • 如果您要触及很多行,例如“本世纪的所有付款记录”,请考虑使用时间条件并将其添加到您的索引中。这可以作为一个穷人的分区和加速查询
  • 限制从数据库加载的列数。通常不需要选择*。如果仅选择索引的列,则从索引执行整个查询,并且需要从磁盘加载真正更少的数据,从而使查询快速启动。但是,如果你只选择*或访问一个额外的无索引列,这意味着必须首先从磁盘加载每个匹配的行。
  • 避免过早优化(例如在...中与...截然不同) - 正如您可以看到其他因素产生更大的影响
  • 插入真实数据:实际行数,具有真实基数(例如使用假身份生成器创建100万客户,但不要将其称为“user1”...“user100000”)并执行执行计划在您更改任何内容之前选择