我做了一个查询,它给了我需要的结果,但速度非常慢。
DB:Mysql
问题:非常慢。
问题:我有什么方法可以加快查询速度!
提前致谢!
SELECT Count(*) AS totalCount
FROM
( SELECT Max(issue_cnt) AS max_count, deal_id, issue_date, penalty_point,
sale_volume, penalty_classify_code
FROM
( SELECT penalty.deal_id, Count(*) AS issue_cnt,
Max(penalty_point) AS max_point,
penalty.issue_date, penalty.penalty_point,
penalty.sale_volume,
penalty.penalty_classify_code
FROM bizinfo.tb_pc_sale_penalty penalty,
( SELECT Max(penalty_point) AS max_point,
penalty.deal_id, penalty.issue_date,
penalty.sale_volume,
penalty.penalty_classify_code
FROM bizinfo.tb_pc_sale_penalty penalty,
bizinfo.tb_deal_info deal
WHERE penalty.deal_id = deal.deal_id
AND penalty.issue_date >= '2016-01-01'
AND penalty.issue_date < '2016-03-16'
AND Date_format(penalty.registe_date, '%Y-%m-%d') <=
Date_format(Now(), '%Y-%m-%d')
GROUP BY deal_id , issue_date
) terms
WHERE penalty.deal_id = terms.deal_id
AND penalty.issue_date = terms.issue_date
AND penalty.sale_volume = terms.sale_volume
AND penalty.penalty_point = terms.max_point
AND penalty.issue_date >= '2016-01-01'
AND penalty.issue_date < '2016-03-16'
AND Date_format(penalty.registe_date, '%Y-%m-%d') <=
Date_format(Now(), '%Y-%m-%d' )
GROUP BY deal_id , penalty.sale_volume , issue_date ,
penalty.penalty_classify_code
) choice
GROUP BY deal_id , issue_date
) selection
left join
( SELECT 1 AS cnt, penalty_classify_code, penalty_point,
process_condition,
deal_id, issue_date, registe_date, company_id
FROM bizinfo.tb_pc_penalty_point_finalize
WHERE issue_date >= '2016-01-01'
AND issue_date < '2016-03-16'
) finalize ON selection.deal_id = finalize.deal_id
AND selection.issue_date = finalize.issue_date
left join
( SELECT Ifnull(SUM(penalty_point), 0) AS point, company_id
FROM bizinfo.tb_pc_penalty_point_finalize
WHERE process_condition = 1
AND penalty_point > 0
AND registe_date >= Date_sub(Curdate(), interval 89 day)
AND registe_date < Date_format(Now(), '%Y-%m-%d')
GROUP BY company_id
) cumulate ON finalize.company_id = cumulate.company_id
left join
( SELECT Count(*) AS cnt, penalty.deal_id, penalty.issue_date
FROM bizinfo.tb_pc_sale_penalty penalty, bizinfo.tb_deal_info deal
WHERE deal.deal_id = penalty.deal_id
AND penalty.issue_date >= '2016-01-01'
AND penalty.issue_date < '2016-03-16'
AND penalty_point < 0
GROUP BY deal_id , issue_date
) suspension ON selection.deal_id = suspension.deal_id
AND selection.issue_date = suspension.issue_date
left join
( SELECT penalty.deal_id, penalty.issue_date, Count(*) AS all_issue_count,
Ifnull(exp.explain_cnt, 0) AS explain_count,
SUM(penalty.penalty_point) AS penalty_cumulative_point,
penalty_point AS penalty_allocate_point, deal.company_id,
deal.md_id, deal.team_id, deal.main_name
FROM
( SELECT deal_id,
CASE WHEN penalty_point > 0
THEN penalty_point
ELSE 0 END AS penalty_point,
issue_date
FROM bizinfo.tb_pc_sale_penalty
) penalty
left join
( SELECT 1 AS explain_cnt, exp.deal_id, exp.issue_date
FROM bizinfo.tb_pc_penalty_explain exp
GROUP BY exp.deal_id , exp.issue_date
) exp ON exp.deal_id = penalty.deal_id
AND exp.issue_date = penalty.issue_date, bizinfo.tb_deal_info deal
WHERE penalty.deal_id = deal.deal_id
GROUP BY penalty.deal_id , penalty.issue_date , deal.company_id
) alltype ON selection.deal_id = alltype.deal_id
AND selection.issue_date = alltype.issue_date, bizinfo.tb_deal_info deal,
bizinfo.tb_partner_member member, bizinfo.tb_partner_member member2,
bizinfo.tb_pc_communication_master_code master,
bizinfo.tb_company_info company
WHERE selection.deal_id = deal.deal_id
AND deal.md_id = member.user_id
AND deal.team_id = member2.user_seq
AND master.group_cd = 'P10080'
AND master.value_cd NOT IN ('p99')
AND master.value_cd = selection.penalty_classify_code
AND alltype.company_id = company.company_id;
答案 0 :(得分:1)
是的,您可以将索引应用于 WHERE 子句中使用的列 就像在selection.deal_id,deal.deal_id,deal.md_id和member.user_id上添加索引一样。 但是在桌子上有太多的索引并不好。
作为一般规则,您应该在所有主键上都有索引(您没有选择),所有外键以及您常用于获取行的任何其他字段。
答案 1 :(得分:1)
在查询中涉及的列上创建INDEX。
FLUSH TABLES
RESET QUERY CACHE
上面的将释放一些内存空间。 祝你好运
答案 2 :(得分:1)
使用FROM a JOIN b ON ...
语法代替FROM a,b WHERE ...
。
FROM ( SELECT ... ) JOIN ( SELECT ... ) ON ...
(或较旧的格式)优化不佳。尽量避免它。
Date_format(Now(), '%Y-%m-%d')
- &gt; CURRENT_DATE()
。
这更简单,更优化;我怀疑它给出了相同的意图&#39;:
Date_format(penalty.registe_date, '%Y-%m-%d') <=
Date_format(Now(), '%Y-%m-%d' )
-->
penalty.registe_date < NOW()
请提供SHOW CREATE TABLE
,以便我们判断索引的效用并了解数据类型。 (示例:issue_date为DATE
还是DATETIME
?)请提供EXPLAIN SELECT
,以便我们查看当前正在执行的查询。
考虑JOIN
是否合适而不是LEFT JOIN
。
您运行的是哪个版本的MySQL?
penalty
可能会受益于INDEX(deal_id, issue_date, sale_volume, penalty_point, registe_date)
- 特别是registe_date
最后一次。
在其中一个早期子查询中,为什么包含deal
? (... FROM bizinfo.tb_pc_sale_penalty penalty, bizinfo.tb_deal_info deal ...
)如果没有deal
,INDEX(deal_id, issue_date)
将是一个非常好的索引。如果您加入deal
,我不确定该推荐什么。
tb_pc_penalty_point_finalize
需要INDEX(issue_date)
。
left join ( SELECT Ifnull(SUM(penalty_point), 0) AS point ...
可以完全删除!这是额外的工作,但您不能使用它生成的point
。而且,由于它是LEFT
,没有人关心SELECT
是否找到了什么。也许其他LEFT JOINs
也没用?
master
可能需要INDEX(group_cd)
; selection
可能需要INDEX(penalty_classify_code)
。