SQL 导致整体查询变慢的子查询

SQL subquery causing overall query to go slow

以下查询需要几分钟(有时无法完成)才能执行。我正在使用 MySQL 数据库。

select 
        customer_name as cust,
        SUM(num_visits) AS visits
     from 
        visit_history
     where
            category = "middleMan"
            and eve_date >= '2014-07-01' and eve_date <= '2015-07-01
            and eve_type='XCG'
            and eve_master IN (select eve_name from master_type_ahj where category = "middleMan"  and eve_date >= '2014-07-01' and eve_date <= '2015-07-01')
     group by
        cust
    order by
        visits  desc 
    limit   
        50

数据库table 包含超过百万条记录。数据被分区。如果我要删除子查询 - and eve_master IN (select eve_name from master_type_ahj where category = "middleMan" and eve_date >= '2014-07-01' and eve_date <= '2015-07-01'),查询将在几分钟内完成。

进入 WHERE 子句的列已编入索引。

无论如何我可以调整这个吗?这里的任何帮助也会帮助我调整一堆相关的查询。我可以在这里寻求帮助吗?

MySQL 通常处理 EXISTSIN 好。所以,这是您的查询:

select customer_name as cust, SUM(num_visits) AS visits
from visit_history
where category = 'middleMan' and
      eve_date >= '2014-07-01' and eve_date <= '2015-07-01 and
      eve_type = 'XCG' and
      exists (select 1
              from master_type_ahj m2
              where m2.eve_master = vh.eve_master
                    m2.category = 'middleMan'  and
                    m2.eve_date >= '2014-07-01' and eve_date <= '2015-07-01'
             )
group by cust
order by visits  desc 
limit 50;

我会推荐 visit_history(category, eve_type, eve_date, eve_master) 上的索引。和 master_type_ahj(eve_master, category, eve_date).

我建议使用实际的 join 会更有效率:

select 
      vh.customer_name as cust,
      SUM(vh.num_visits) AS visits
    from 
      visit_history as vh
      inner join 
      master_type_ahj as mt on vh.eve_master = mt.eve_name
    where
      vh.category = "middleMan"
      and vh.eve_date >= '2014-07-01' and vh.eve_date <= '2015-07-01
      and vh.eve_type='XCG'
      and mt.category = "middleMan"  
      and mt.eve_date >= '2014-07-01' and mt.eve_date <= '2015-07-01'

您还可以通过使用 explain 查看 mysql 实际处理您的查询的内容来了解​​更多信息。

这是使用派生 table

的另一种方法
select 
    customer_name as cust,
    sum(num_visits) as visits
from visit_history
join (
    select distinct eve_name from master_type_ahj 
    where category = "middleMan"  
    and eve_date >= '2014-07-01' 
    and eve_date <= '2015-07-01'
) t on t.eve_name = visit_history.eve_master
where category = "middleMan"
    and eve_date >= '2014-07-01' and eve_date <= '2015-07-01'
    and eve_type='XCG'
group by cust
order by visits desc 
limit 50