Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/heroku/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
需要关于优化有趣的MySQL查询的帮助吗 查询优化_Mysql_Sql_Database Performance_Query Performance_Sqlperformance - Fatal编程技术网

需要关于优化有趣的MySQL查询的帮助吗 查询优化

需要关于优化有趣的MySQL查询的帮助吗 查询优化,mysql,sql,database-performance,query-performance,sqlperformance,Mysql,Sql,Database Performance,Query Performance,Sqlperformance,我需要有关优化此查询性能的帮助。此查询主要查找与case-when条件列表匹配的所有时段的累计和 目前,此查询运行大约需要100秒,因为它按数据库中的每个帐户分组。我试图通过查看explain输出来优化它,但我想不出一种方法来让它工作。以下是解释输出: 理想时间为10秒或更短。期待您的回复。谢谢大家! SET @date = '2017-05-17'; SET @offset = 1; select b.act, CASE WHEN b.jdt <= DATE_SUB(@date,

我需要有关优化此查询性能的帮助。此查询主要查找与case-when条件列表匹配的所有时段的累计和

目前,此查询运行大约需要100秒,因为它按数据库中的每个帐户分组。我试图通过查看explain输出来优化它,但我想不出一种方法来让它工作。以下是解释输出:

理想时间为10秒或更短。期待您的回复。谢谢大家!

SET @date = '2017-05-17';
SET @offset = 1;

select 
b.act,
CASE 
WHEN b.jdt <= DATE_SUB(@date, INTERVAL 5 DAY) AND b.jdt >= DATE_SUB(@date, INTERVAL 5 + @offset DAY) AND DATEDIFF(a.dt,b.jdt) <=5 THEN 5
WHEN b.jdt <= DATE_SUB(@date, INTERVAL 13 DAY) AND b.jdt >= DATE_SUB(@date, INTERVAL 13 + @offset DAY) AND DATEDIFF(a.dt,b.jdt) <=13 THEN 13
WHEN b.jdt <= DATE_SUB(@date, INTERVAL 25 DAY) AND b.jdt >= DATE_SUB(@date, INTERVAL 25 + @offset DAY) AND DATEDIFF(a.dt,b.jdt) <=25 THEN 25
WHEN b.jdt <= DATE_SUB(@date, INTERVAL 45 DAY) AND b.jdt >= DATE_SUB(@date, INTERVAL 45 + @offset DAY) AND DATEDIFF(a.dt,b.jdt) <=45 THEN 45
WHEN b.jdt <= DATE_SUB(@date, INTERVAL 75 DAY) AND b.jdt >= DATE_SUB(@date, INTERVAL 75 + @offset DAY) AND DATEDIFF(a.dt,b.jdt) <=75 THEN 75
WHEN b.jdt <= DATE_SUB(@date, INTERVAL 105 DAY) AND b.jdt >= DATE_SUB(@date, INTERVAL 105 + @offset DAY) AND DATEDIFF(a.dt,b.jdt) <=105 THEN 105
WHEN b.jdt <= DATE_SUB(@date, INTERVAL 135 DAY) AND b.jdt >= DATE_SUB(@date, INTERVAL 135 + @offset DAY) AND DATEDIFF(a.dt,b.jdt) <=135 THEN 135
WHEN b.jdt <= DATE_SUB(@date, INTERVAL 165 DAY) AND b.jdt >= DATE_SUB(@date, INTERVAL 165 + @offset DAY) AND DATEDIFF(a.dt,b.jdt) <=165 THEN 165
WHEN b.jdt <= DATE_SUB(@date, INTERVAL 195 DAY) AND b.jdt >= DATE_SUB(@date, INTERVAL 195 + @offset DAY) AND DATEDIFF(a.dt,b.jdt) <=195 THEN 195
WHEN b.jdt <= DATE_SUB(@date, INTERVAL 225 DAY) AND b.jdt >= DATE_SUB(@date, INTERVAL 225 + @offset DAY) AND DATEDIFF(a.dt,b.jdt) <=225 THEN 225
ELSE 'other' END AS 'period',

SUM(CASE WHEN a.type = 'JN' AND a.paid = 'Y' AND a.upgraded=0 THEN 1 ELSE 0 END) AS 'Paid_Joins',
SUM(CASE WHEN a.type IN ('SL','RL') AND ttype !='Purchase' THEN (a.amt_usd/100 - a.vat_usd/100) END) AS 'Revenue_Amount'

FROM __customer b
JOIN  __transaction a on b.uid = a.primary_uid 

WHERE
b.affiliate_act regexp '^[a-zA-Z]+[0-9]+'
AND a.dt <= @date 
AND a.dt >= DATE_SUB(@date, INTERVAL 225 + @offset DAY)
AND b.jdt >= DATE_SUB(@date, INTERVAL 225 + @offset DAY)
GROUP BY 1,2
HAVING period != 'other'
SET@date='2017-05-17';
设置@offset=1;
选择
b、 行动,
案例

当b.jdt=DATE\u SUB(@DATE,INTERVAL 5+@offset DAY)和DATEDIFF(a.dt,b.jdt)时,确保a.primary\u uid、a.dt和b.uid都被索引。尝试一个复合a.dt,a.primary\u uid

处理5187819行后,根据优化器对代码的解释方式,DATE_SUB可能被调用103756380次。这就是为什么我建议将它从将被调用十次的查询中拉出

尝试预先计算日期间隔,这样就不会为case语句的每次迭代计算日期间隔。您还可以预先计算日期间隔减去偏移量。如果这有帮助的话,我会留给你的

SET @date = '2017-05-17';
SET @offset = 1;
SET @dtint5 = DATE_SUB(@date, INTERVAL 5 DAY);
SET @dtint13 = DATE_SUB(@date, INTERVAL 13 DAY);
SET @dtint25 = DATE_SUB(@date, INTERVAL 25 DAY);
SET @dtint45 = DATE_SUB(@date, INTERVAL 45 DAY);
SET @dtint75 = DATE_SUB(@date, INTERVAL 75 DAY);
SET @dtint105 = DATE_SUB(@date, INTERVAL 105 DAY);
SET @dtint135 = DATE_SUB(@date, INTERVAL 135 DAY);
SET @dtint165 = DATE_SUB(@date, INTERVAL 165 DAY);
SET @dtint195 = DATE_SUB(@date, INTERVAL 195 DAY);
SET @dtint225 = DATE_SUB(@date, INTERVAL 225 DAY);

select 
b.act,
CASE 
WHEN b.jdt <= @dtin5 AND b.jdt >= @dtint5 - @offset AND DATEDIFF(a.dt,b.jdt) <=5 THEN 5
WHEN b.jdt <= @dtint13 AND b.jdt >= @dtint13 - @offset AND DATEDIFF(a.dt,b.jdt) <=13 THEN 13
WHEN b.jdt <= @dtint25 AND b.jdt >= @dtint25 - @offset AND DATEDIFF(a.dt,b.jdt) <=25 THEN 25
WHEN b.jdt <= @dtint45 AND b.jdt >= @dtint45 - @offset AND DATEDIFF(a.dt,b.jdt) <=45 THEN 45
WHEN b.jdt <= @dtint75 AND b.jdt >= @dtint75 - @offset AND DATEDIFF(a.dt,b.jdt) <=75 THEN 75
WHEN b.jdt <= @dtint105 AND b.jdt >= @dtint105 - @offset AND DATEDIFF(a.dt,b.jdt) <=105 THEN 105
WHEN b.jdt <= @dtint135 AND b.jdt >= @dtint135 - @offset AND DATEDIFF(a.dt,b.jdt) <=135 THEN 135
WHEN b.jdt <= @dtint165 AND b.jdt >= @dtint165 - @offset AND DATEDIFF(a.dt,b.jdt) <=165 THEN 165
WHEN b.jdt <= @dtint195 AND b.jdt >= @dtint195 - @offset AND DATEDIFF(a.dt,b.jdt) <=195 THEN 195
WHEN b.jdt <= @dtint225 AND b.jdt >= @dtint225 - @offset AND DATEDIFF(a.dt,b.jdt) <=225 THEN 225
ELSE 'other' 
END AS 'period',

SUM(CASE WHEN a.type = 'JN' AND a.paid = 'Y' AND a.upgraded=0 THEN 1 ELSE 0     END) AS 'Paid_Joins',
SUM(CASE WHEN a.type IN ('SL','RL') AND ttype !='Purchase' THEN (a.amt_usd/100 - a.vat_usd/100) END) AS 'Revenue_Amount'

FROM __customer b
JOIN  __transaction a on b.uid = a.primary_uid 

WHERE a.dt <= @date

GROUP BY 1,2
SET@date='2017-05-17';
设置@offset=1;
设置@dtint5=DATE\u SUB(@DATE,间隔5天);
设置@dtint13=日期(@DATE,间隔13天);
设置@dtint25=日期(@DATE,间隔25天);
设置@dtint45=日期(@DATE,间隔45天);
设置@dtint75=日期(@DATE,间隔75天);
设置@dtint105=日期(@DATE,间隔105天);
设置@dtint135=日期(@DATE,间隔135天);
设置@dtint165=日期(@DATE,间隔165天);
设置@dtint195=日期(@DATE,间隔195天);
设置@dtint225=日期(日期,间隔225天);
选择
b、 行动,
案例

当b.jdt=@dtint5-@offset和DATEDIFF(a.dt,b.jdt)时,您试图做的是将帐户活动分解为客户历史交易的存储桶范围。然而,看看日期测试,看起来每个桶基本上是2天,比如

5 days results in 5/11-5/12
13 days results in 5/3-5/4
25 days results in 4/21-4/22
取而代之的是一整桶的ex:

5/11 - 5/17
5/2  - 5/10
4/21 - 5/2
??? - 4/20
如果我使用您的日期/间隔设置运行

SELECT DATE_SUB(@date, INTERVAL 5 DAY) - @offset   (result 20170511 looking like a number, not a date)
and
SELECT DATE_SUB(@date, INTERVAL 5 DAY) (result 2017-05-12 expected date)
因此,您的范围将代表2017-05-11=jdt和jdt<'2017-05-12'
这将为您提供从5月11日到晚上11:59:59的所有信息,但不包括5月12日的日期。如果你真的想像我描述的那样做铲斗范围,我会为你提供一个更干净的解决方案,请告诉我


此外,为了提高性能,您要查看给定日期之前的所有事务,因此您要浏览几乎整个事务表。表中还有哪些“类型”的事务可以通过索引帮助丢弃?似乎您只关心“JN”、“SL”和“RL”。这就是说,我会在您的事务表上有一个索引(type,dt)。对于您的客户表,我会在(uid,act)上有一个覆盖索引,这样就不需要转到客户的所有页面数据来检索他们的帐户。它根据UID对联接进行限定,帐户#随车而来。

性能问题应包括
解释分析
以及一些关于表大小、索引、当前时间性能、期望时间等的信息。
是一个相对术语,我们需要一个实际值进行比较。虽然我不认为MySQL中有解释分析,但我尝试附加一些类似的东西,可能会有所帮助。我们需要您的创建表和索引,这样我们就可以了解您已经拥有了什么。我提供的链接告诉您如何获得查询执行计划。但是对于您发布的显示
全表扫描的图片
,您似乎没有日期索引。您可能需要一个复合索引
(uid,date)
我告诉过您使用复合索引。另外,你正在试图解决一个大问题,而不是试图先解决一个小问题。删除所有
案例
分组方式
使用新索引测试
位置
,如果情况好转,开始添加更多部分。显示创建索引。那张桌子上有多少天?有没有可能所有的日期都在这个范围内?谢谢。然而,我试图对所有日期进行硬编码,但看起来查询时间根本没有改善。在聚合之前(a.dt<@date)处理了多少行?我这样做是因为case语句每行执行一次,然后对行进行聚合。删除硬编码日期并不能解决这个问题。如我所示,在case语句之外对其进行编码。这不是日期的硬编码,而是我试图从select迭代中删除的函数调用date\u sub。为where子句添加了更多条件以减少正在处理的行数。继续为每个查询变量使用EXPLAIN输出。尝试在表事务上定义一个复合索引primary_uid,dt,它是要从解释输出中删除的“usingtemporary”和“usingfilesort”。建议您也尝试在查询中颠倒表的顺序:从uu事务t JOIN u客户c ON c.uid=t.primary_uid(ps:我不喜欢别名暗示像a、b、c这样的顺序)另外,我在事务上添加了复合索引(type,dt),在客户上添加了(uid,act),但是explain输出仍然显示相同的结果。我使用了single day来测试性能,但是每个bucket的日期范围可能会动态变化,它们取决于两个参数“date”和“offset”
SELECT DATE_SUB(@date, INTERVAL 5 DAY) - @offset   (result 20170511 looking like a number, not a date)
and
SELECT DATE_SUB(@date, INTERVAL 5 DAY) (result 2017-05-12 expected date)
SELECT DATE_SUB(@date, INTERVAL 5+@offset DAY) (result 2017-05-11  expected date)
and
SELECT DATE_SUB(@date, INTERVAL 5 DAY) (result 2017-05-12 expected date)
'2017-05-11' >= jdt AND jdt < '2017-05-12'