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 通常处理 EXISTS
比 IN
好。所以,这是您的查询:
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
以下查询需要几分钟(有时无法完成)才能执行。我正在使用 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 通常处理 EXISTS
比 IN
好。所以,这是您的查询:
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