多重选择MySQL查询的工作方式

时间:2018-08-12 14:05:27

标签: mysql sql

我对与mysql相关的基本问题有疑问。考虑如下查询:

select * 
  from logdb_new.new_tbl_logrecord as alltable 
  where alltable.SessionID in (
    select distinct SessionID from logdb_new.new_tbl_health
  )

我想知道在执行此查询期间是否使用SessionID表的new_tbl_health上的索引。换句话说,告诉我查询的第二部分select distinct SessionID from logdb_new.new_tbl_health是否首先执行以生成列表,然后执行主查询,或者它使用索引或new_tbl_health上的任何内容来为其中的每一行查找sessionID new_tbl_logrecord。

我想减少查询的执行时间。 logdb_new.new_tbl_logrecord拥有近3000万条记录和logdb_new.new_tbl_health的不同SessionID 超过8万个结果。请让我知道是否有更好的查询,以减少执行时间。

3 个答案:

答案 0 :(得分:4)

我不认为这里可以使用new_tbl_health.SessionID上的索引,因为子查询的结果是中间结果。但是,我们可以尝试使用内部联接重写您的查询:

SELECT *
FROM logdb_new.new_tbl_logrecord t1
INNER JOIN logdb_new.new_tbl_health t2
    ON t1.SessionID = t2.SessionID;

除了索引可能在这里可用之外,内部联接版本的优点在于,优化器现在可以自由选择要在联接的左侧/右侧显示哪个表。

作为附带说明,如果您想坚持当前的方法,我认为您可以删除不同的选择并仅使用:

SELECT SessionID FROM logdb_new.new_tbl_health

如果出现重复的SessionID值,则在逻辑上不会更改查询的结果。但是调用DISTINCT可能意味着查询计划可能必须进行一些汇总,也许是不必要的。

答案 1 :(得分:2)

我不认为in会使用子查询上的索引(尽管优化器有时会做得很棒)。但是,您可以改用exists,它将使用索引:

select lr.* 
from logdb_new.new_tbl_logrecord lr
where exists (select 1
              from logdb_new.new_tbl_health nth
              where lr.SessionID = nth.SessionID
             );

答案 2 :(得分:1)

查询:

select distinct SessionID from logdb_new.new_tbl_health

是“不相关的子查询”。大多数(如果不是全部)数据库将首先执行它,以获取ID列表,并将使用该列表从外部查询中选择行。

不利的一面是,该查询不能照原样进行“流水线化”,因此它将需要实现整个id值集。如果改为使用JOIN,则该查询可能已经被流水线处理,并且需要更少的内存。无论如何,只有当子查询返回的id数量很大时,这种优化才有意义。不用担心。