php - 如何使用 MySQL 中的报告子查询优化多个连接的查询

标签 php mysql

我在我的应用程序中定义了以下表格,以根据培训日期获取每个地区的报告。

wi_individual_g(ind_id, ind_district_id, ...)
wi_individual_p(ind_id,prg_id, ind_dalit (yes/no), ind_madhesi (yes/no), ...)
wi_training(trn_id, trn_start_date, trn_ben_type, ...)
wi_indv_training(trn_id, ind_id)
wi_district(dst_id,dst_name)

我的问题:必须生成报告以统计在给定 trn_start_date 期间与培训相关的地区个人。该应用程序具有预定义的日期范围和季度定义如下:

$quarter=array('y1q3'=>array('2013-02-01','2013-03-31'),'y1q4'=>array('2013-04-01','2013-06-30')
,'y2q1'=>array('2013-07-01','2013-09-30'),'y2q2'=>array('2013-10-01','2013-012-31'),'y2q3'=>array('2014-01-01','2014-03-31'),'y2q4'=>array('2014-04-01','2014-06-30')
,'y3q1'=>array('2014-07-01','2014-09-30'),'y3q2'=>array('2014-10-01','2014-012-31'),'y3q3'=>array('2015-01-01','2015-03-31'),'y3q4'=>array('2015-04-01','2015-06-30')
,'y4q1'=>array('2015-07-01','2015-09-30'),'y4q2'=>array('2015-10-01','2015-012-31'),'y4q3'=>array('2016-01-01','2016-03-31'),'y4q4'=>array('2016-04-01','2016-06-30')
,'y5q1'=>array('2016-07-01','2016-09-30'),'y5q2'=>array('2016-10-01','2016-012-31'),'y5q3'=>array('2017-01-01','2017-03-31'),'y5q4'=>array('2017-04-01','2017-06-30')
,'y6q1'=>array('2017-07-01','2017-09-30'),'y6q2'=>array('2017-10-01','2017-012-31'),'y6q3'=>array('2018-01-01','2018-03-31'),'y6q4'=>array('2018-04-01','2018-06-30')); 

如果 trn_start_date 选择为 Y4Q4,则查询必须按地区计算每个日期范围内的个人:Y1(Q1-Q4)、Y2(Q2-Q4)、Y3(Q1 -Q4), Y4(Q1-Q4) 单独查询为:

Y1  Y2    Y3    Y4  Y5  Y6
8   3948  3511  0   0   0

作为解决方案,我应用了以下查询:

SELECT wi_district.dst_name, 
COUNT(DISTINCT(CASE WHEN wi_training.trn_start_date BETWEEN '2017-07-01' AND '2018-06-30' AND 
ind_dalit='yes' THEN wi_individual_g.ind_id END)) AS y6 , 
COUNT(DISTINCT(CASE WHEN wi_training.trn_start_date BETWEEN '2016-07-01' AND '2017-06-30' AND     ind_dalit='yes' THEN wi_individual_g.ind_id END)) AS y5 , 
COUNT(DISTINCT(CASE WHEN wi_training.trn_start_date BETWEEN '2015-07-01' AND '2016-06-30' AND ind_dalit='yes' THEN wi_individual_g.ind_id END)) AS y4 , 
COUNT(DISTINCT(CASE WHEN wi_training.trn_start_date BETWEEN '2014-07-01' AND '2015-06-30' AND ind_dalit='yes' THEN wi_individual_g.ind_id END)) AS y3 , 
COUNT(DISTINCT(CASE WHEN wi_training.trn_start_date BETWEEN '2013-07-01' AND '2014-06-30' AND ind_dalit='yes' THEN wi_individual_g.ind_id END)) AS y2 , 
COUNT(DISTINCT(CASE WHEN wi_training.trn_start_date BETWEEN '2013-02-01' AND '2013-06-30' AND ind_dalit='yes' THEN wi_individual_g.ind_id END)) AS y1 
FROM wi_individual_g 
INNER JOIN wi_individual_p ON wi_individual_p.ind_id=wi_individual_g.ind_id AND wi_individual_g.ind_is_recepient='yes' 
INNER JOIN wi_district ON wi_district.dst_id=wi_individual_g.ind_district_id AND wi_individual_g.ind_deleted=0 
INNER JOIN wi_indv_training ON wi_indv_training.ind_id=wi_individual_g.ind_id AND wi_indv_training.is_deleted=0 
INNER JOIN wi_training ON wi_training.trn_id=wi_indv_training.trn_id AND wi_training.trn_deleted=0 AND wi_training.trn_beneficiary_type=2 AND wi_training.trn_start_date <='2018-06-30' 
GROUP BY wi_district.dst_name

但是这个查询需要超过 5 分钟才能执行,这是最糟糕的。我还在字段上应用了索引,但取得了相同的结果。 如果有人为我提供最佳解决方案,我将不胜感激。

最佳答案

我找到了将性能提高 3 倍的方法:

At first : the query took around 128 secs
After suggestion: the query took around 78 secs
Further modification: the query took around 23 secs
---------------------------------------------------------------------------------
SELECT d.dst_name,
COUNT(DISTINCT(CASE WHEN a.trn_start_date BETWEEN '2014-07-01' AND '2015-06-30' THEN a.ind_id END)) AS y3 , 
COUNT(DISTINCT(CASE WHEN a.trn_start_date BETWEEN '2013-07-01' AND '2014-06-30' THEN a.ind_id END)) AS y2 , 
COUNT(DISTINCT(CASE WHEN a.trn_start_date BETWEEN '2013-02-01' AND '2013-06-30' THEN a.ind_id END)) AS y1  
FROM 
(
    SELECT g.ind_district_id,g.ind_id,t.trn_start_date,t.trn_beneficiary_type
    FROM wi_individual_g g
    INNER JOIN wi_indv_training wit ON g.ind_id = wit.ind_id AND wit.is_deleted = 0 AND g.ind_deleted=0 AND g.ind_is_recepient='yes'
    INNER JOIN wi_training t ON wit.trn_id = t.trn_id AND t.trn_beneficiary_type=2 AND t.trn_deleted = 0
) a
INNER JOIN wi_individual_p p ON p.ind_id=a.ind_id
INNER JOIN wi_district d ON d.dst_id=a.ind_district_id
WHERE p.ind_dalit='yes'
GROUP BY d.dst_name;

整体而言,性能比我之前的查询提高了 6 倍。感谢@DRapp 的建议

如果有人有提高性能的最佳解决方案,我要感谢他!

关于php - 如何使用 MySQL 中的报告子查询优化多个连接的查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27414432/

相关文章:

mysql - 仅当字段已填充且与其他字段值相同时才计数

mysql 在where子句中显式引用table.column

mysql - 如果没有可用内容,则不显示菜单项

mysql - konakart安装mysql数据库

php - 将年龄放入年龄组桶中的清理功能 - 可能吗?

php - 将值从 PHP 发送到 jQuery

java - 检索 JSON 数组并将其放入 java 中的数组中?

php - 我已经修改了 php_ini,但仍然收到 PHP 警告 POST Content-Length 超出限制

mysql - 如何获取每个用户给出解决方案的多次平均值(查询)

php - 我如何使用 php 和 mysql 上传音乐