Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/69.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/5/sql/86.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 查询内部where子句存在查询性能问题_Mysql_Sql_Performance_Database Performance - Fatal编程技术网

Mysql 查询内部where子句存在查询性能问题

Mysql 查询内部where子句存在查询性能问题,mysql,sql,performance,database-performance,Mysql,Sql,Performance,Database Performance,我有以下一些复杂的sql查询,由于where子句中的内部查询,它的性能非常糟糕。在某些情况下,它需要超过一分钟。有人知道如何重写此查询以获得更好的性能吗? 查询: SELECT DISTINCT t.id as taskId, t.name as taskName, t.startdate as taskStartDate, t.enddate as taskEndDate, t.proj_id as taskProjectId FROM PROJECT p, EMPL_PROJ

我有以下一些复杂的sql查询,由于where子句中的内部查询,它的性能非常糟糕。在某些情况下,它需要超过一分钟。有人知道如何重写此查询以获得更好的性能吗? 查询:

SELECT DISTINCT t.id as taskId, t.name as taskName, 
  t.startdate as taskStartDate, t.enddate as taskEndDate, 
  t.proj_id as taskProjectId 
FROM PROJECT p, EMPL_PROJ ep, TASK t, TIMERECORD tr 
WHERE 
  ep.empl_id = ? AND 
  ep.proj_id = p.id AND 
  ep.proj_id = t.proj_id AND 
  ((p.startdate IS NULL AND p.enddate IS NULL) OR 
   (p.startdate IS NULL AND p.enddate >= ?) OR 
   (p.enddate IS NULL AND p.startdate <= ? + INTERVAL 6 DAY) OR 
   (p.startdate <= ? + INTERVAL 6 DAY AND p.enddate >= ?) ) AND 
  ((t.startdate IS NULL AND t.enddate IS NULL) OR 
   (t.startdate IS NULL AND t.enddate >= ?) OR 
   (t.enddate IS NULL AND t.startdate <= ? + INTERVAL 6 DAY) OR 
  (t.startdate <= ? + INTERVAL 6 DAY AND t.enddate >= ?)) AND 
  (
   (ep.empl_id = tr.empl_id AND 
    ep.proj_id = tr.proj_id AND 
    t.id = tr.task_id AND tr.day <= ? + INTERVAL 7 DAY AND 
    tr.day >= ? + INTERVAL -14 DAY
   ) OR 
   (
    (SELECT count(*) 
     FROM TIMERECORD tr2 
     WHERE 
     tr2.empl_id=ep.empl_id AND 
     tr2.proj_id=p.id AND tr2.day <= ? + INTERVAL 7 DAY AND 
     tr2.day >= ? + INTERVAL -14 DAY) <= 0
    )
  ) 
我使用的是mysql服务器5.1.40

编辑2: 带着我的评论和回答,我来到了这个查询,它在一秒钟内执行,几乎一分钟内就完成了

SELECT DISTINCT t.id as taskId, t.name as taskName, 
  t.startdate as taskStartDate, t.enddate as taskEndDate, 
  t.proj_id as taskProjectId 
FROM (PROJECT p INNER JOIN EMPL_PROJ ep ON  ep.proj_id = p.id)  
  INNER JOIN TASK t ON p.id=t.proj_id 
  INNER JOIN TIMERECORD tr ON tr.empl_id=ep.empl_id AND tr.proj_id=ep.proj_id 
    AND tr.task_id=t.id
WHERE 
  ep.empl_id = ? AND 
  ((p.startdate IS NULL AND p.enddate IS NULL) OR 
   (p.startdate IS NULL AND p.enddate >= ?) OR 
   (p.enddate IS NULL AND p.startdate <= ? + INTERVAL 6 DAY) OR 
   (p.startdate <= ? + INTERVAL 6 DAY AND p.enddate >= ?) ) AND 
  ((t.startdate IS NULL AND t.enddate IS NULL) OR 
   (t.startdate IS NULL AND t.enddate >= ?) OR 
   (t.enddate IS NULL AND t.startdate <= ? + INTERVAL 6 DAY) OR 
   (t.startdate <= ? + INTERVAL 6 DAY AND t.enddate >= ?)) AND 
  (
   (
    tr.day <= ? + INTERVAL 7 DAY AND 
    tr.day >= ? + INTERVAL -14 DAY
   ) OR 
   (
    NOT EXISTS(SELECT *
      FROM TIMERECORD tr2 INNER JOIN EMPL_PROJ ON tr2.empl_id=EMPL_PROJ.empl_id 
        INNER JOIN PROJECT ON PROJECT.id=tr2.proj_id
      WHERE 
       tr2.day BETWEEN ? + INTERVAL -14 DAY AND ? + INTERVAL 7 DAY)
   )
  ) 
  ORDER BY p.id, t.id
最大的贡献是答案表明了我标记为正确的notexists方法,以及不混合显式连接和隐式连接的注释。
谢谢大家

当您似乎只需要一个不存在的

(
(SELECT count(*) 
 FROM TIMERECORD tr2 
 WHERE 
 tr2.empl_id=ep.empl_id AND 
 tr2.proj_id=p.id AND tr2.day <= ? + INTERVAL 7 DAY AND 
 tr2.day >= ? + INTERVAL -14 DAY) <= 0
)
取代

(
NOT EXISTS(SELECT * 
 FROM TIMERECORD tr2 
 WHERE 
 tr2.empl_id=ep.empl_id AND 
 tr2.proj_id=p.id AND tr2.day <= ? + INTERVAL 7 DAY AND 
 tr2.day >= ? + INTERVAL -14 DAY)
)

现在,如果确实存在一条时间记录,where子句的这一部分将短路到FALSE NOT TRUE,而不必计算每个时间记录。

摆脱子查询

一,。使用列emp_id、proj_id、count*分别计算所有emp_id和proj_id的子查询,其中日期在所需范围内。这是一个简单的分组查询

select empl_id,proj_id,count(*) as ct from TIMERECORD 
where day between (? + INTERVAL -14 DAY) and (? + INTERVAL 7 DAY)
group by empl_id,proj_id;
将此结果集称为B

二,。像现在一样计算剩余的查询。将此结果集称为A

三,。使用A&B中常见的列emp_id、proj_id进行左外连接B

然后,在where子句中,您可以检查B.ct列中的值,对于给定时间范围的时间记录表中未找到任何条目的所有emp_id、proj_id组合,该值将为null


实际上你甚至不需要计数,因为你不在乎实际的计数。但是,让我不要让它变得太复杂。

可能可以通过尝试使用可疑部分和不使用可疑部分的查询来升级到确定性,以查看其引入是否会导致速度缓慢。这样做还可以清除不相关的代码,从而创建一个新的问题,从而使您的问题更适用于其他人,也更容易解决answerable@Bohemian:我已经这样做了,可以肯定的是,内部select语句是性能问题的原因。只是不知道如何在没有它的情况下重写查询。步骤1将使用较新的联接语法,而不是使用where filters内容的旧的不推荐交叉联接。@jb10210 internal JOIN emp_Proj ep ON ep.Proj_id=p.id例如。它使连接关系更加明显。在连接语句中使用逗号,您可能会在empll_项目和任务之间进行交叉连接。这就是为什么要花这么长时间的原因。你永远不想混合隐式连接和显式连接,否则结果往往是不幸的。但是你不应该写隐式连接,它们在20年前就被替换了,没有理由在2012年使用它们!它已经显著地将查询响应时间从+10秒减少到大约5-6秒。但是在where子句中没有select的同一个查询会发送更多的数据,运行时间大约为1s。所以这应该减少一些。-1-你已经11个月了,现在应该知道代码标记是如何工作的了。@Priyank感谢between关键字,我不知道它的存在+1@JNK你是谁?我不在乎那样的事会不会冒犯你。如果你对它无礼的话,情况就更糟了。我有我的解释为什么我没有这么做,但我不欠你一个。@Priyank-我只是另一个用户。我没有粗鲁,但不编辑代码是非常懒惰的,这表明你并不真正关心那些不得不阅读你文章的人。我没有暗示你欠我一个解释,我也不必解释反对票,但我解释了。@JNK如果我不在乎,我就不会回答了。第二,我不太使用stackoverflow来了解它的所有特性。11个月并不能说明我用了多少。