mysql - where 子句中查询的查询性能问题

标签 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 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

最大的贡献是建议使用 NOT EXISTS 方法(我标记为正确)的答案以及不要混合使用 explicitimplicit JOIN 的。

感谢大家!

最佳答案

当您似乎只需要一个 NOT EXISTS 时,您正在使用 COUNT(*)...

(
(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)
)

现在,如果 TIMERECORD 确实存在,那部分 where 子句将短路为 FALSE(NOT TRUE),而不必计算每个 TIMERECORD。

关于mysql - where 子句中查询的查询性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9872045/

相关文章:

php - Mysql/php 按 varchar 的第二个单词排序

运行大约一天或更长时间后,Java ConcurrentHashMap putIfAbsent 变慢

android - Honeycomb (TF101) 上的 Canvas /位图和 alpha 混合性能问题

c# - C#中如何从数据库中获取图片

mysql - 列表中的每个值在另一个表的列中出现的次数。数据库

sql - 获取最高价格商品的 ID

mysql - 无法创建表 'mydb.contact'(错误号 : 150)

performance - 有什么加速静态分析工具 PC-Lint 的技巧吗?有使用 .LOB 文件的经验吗?

php - 我如何获取关键字中的文本?

mysqltuner推荐建议