我想优化这个查询,需要花费大量的时间来执行

时间:2014-11-26 04:01:54

标签: mysql sql performance select query-optimization

si想要优化这个需要大量时间执行的查询。

SELECT DISTINCT
  j1.job_id,
  j1.job_name,
  j1.client_id,
  j1.job_status_id,
  j1.int_job_status_id,
  j1.job_type_id,
  j1.job_due_date,
  j1.job_received,
  c1.client_name,
  c1.id,
  j1.period,
  j1.notes,
  j1.staff_notes,
  j1.job_genre,
  j1.job_submitted,
  j1.mas_Code,
  DATE_FORMAT(j1.job_completed_date, '%d/%m/%Y')    completedDate,
  j1.invoiceno,
  j1.is_active,
  p1.name,
  s1.job_status
FROM CLIENT c1,
  pr_practice p1,
  sub_subactivity sa,
  job_status s1,
  job j1
  LEFT JOIN task t
    ON j1.job_id = t.job_id
  LEFT JOIN task_assign ta
    ON ta.task_id = t.task_id
WHERE j1.client_id = c1.client_id
    AND c1.id = p1.id
    AND t.job_id = j1.job_id
    AND sa.sub_Code = j1.job_type_id
    AND j1.job_status_id = s1.job_status_id
    AND j1.discontinue_date IS NULL
    AND j1.job_submitted = 'Y'
    AND j1.job_status_id <> 7
    AND p1.id = c1.id
    AND (j1.job_type_id IN(8,5,6,9,19,19,7,16,17)
         AND (FIND_IN_SET(134,p1.sr_manager)
               OR FIND_IN_SET(134,p1.manager)
               OR FIND_IN_SET(134,p1.tl1)
               OR FIND_IN_SET(134,p1.tl2)
               OR FIND_IN_SET(134,p1.tl3)
               OR FIND_IN_SET(134,p1.tl4)
               OR FIND_IN_SET(134,p1.sales))
          OR ta.assignee_id IN(134))
    AND j1.is_active = 1
ORDER BY j1.job_received DESC, j1.job_id DESC
LIMIT 0,25

客户表

client_id int(11)  | id int(11) (practice Id)

练习表

id int(11) | sr_manager | manager | t1 |t2 |t3 |t4 |sales varchar(255)

工作表

j1.job_id,   j1.job_name,   j1.client_id,   j1.job_status_id,   j1.int_job_status_id,  j1.job_type_id,   j1.job_due_date,   j1.job_received,  j1.period,
  j1.notes,  j1.staff_notes,  j1.job_genre,  j1.job_submitted,  j1.mas_Code etc.

任务表

task_id | id (practice id) | client_id | job_id 

任务受让人

id | task_id | assignee_id

请指教!

2 个答案:

答案 0 :(得分:0)

试试这个:

SELECT DISTINCT j1.job_id, j1.job_name, j1.client_id, j1.job_status_id, 
         j1.int_job_status_id, j1.job_type_id, j1.job_due_date, j1.job_received, 
         c1.client_name, c1.id, j1.period, j1.notes, j1.staff_notes, j1.job_genre, 
         j1.job_submitted, j1.mas_Code, DATE_FORMAT(j1.job_completed_date, '%d/%m/%Y') completedDate, 
         j1.invoiceno, j1.is_active, p1.name, s1.job_status
FROM CLIENT c1, 
INNER JOIN pr_practice p1 ON c1.id = p1.id 
INNER JOIN job j1 ON j1.client_id = c1.client_id AND j1.is_active = 1
INNER JOIN sub_subactivity sa ON sa.sub_Code = j1.job_type_id
INNER JOIN job_status s1 ON j1.job_status_id = s1.job_status_id
LEFT JOIN task t ON j1.job_id = t.job_id
LEFT JOIN task_assign ta ON ta.task_id = t.task_id
WHERE j1.discontinue_date IS NULL AND j1.job_submitted = 'Y' AND 
        j1.job_status_id <> 7 AND j1.job_type_id IN (8,5,6,9,19,19,7,16,17) AND 
       FIND_IN_SET(134, CONCAT_WS(',', p1.sr_manager, p1.manager, p1.tl1, p1.tl2, p1.tl3, p1.tl4, p1.sales, ta.assignee_id))    
ORDER BY j1.job_received DESC, j1.job_id DESC
LIMIT 0,25

答案 1 :(得分:0)

问题并不能识别任何表格上的任何索引。

SQL性能的关键是了解优化器可用的操作,以及MySQL如何确定从可用的操作中选择哪些操作。拥有合适的索引可以使MySQL能够利用这些索引来实现更高效的执行计划。

如果没有EXPLAIN的输出,我们就会猜测执行计划。

我们对性能降低的最初的下意识反应是添加适当的指数。或者第二个想法是,当谓词包含OR条件时,MySQL并不总能做出最有效的选择。 LIMIT子句最后应用于处理... MySQL将在应用LIMIT之前处理整个结果集上的DISTINCT和ORDER BY操作。并且Using filesort操作在大型集合上可能很昂贵。

作为定义可能合适的索引的第一步:

... ON job (discontinue_date, is_active, job_submitted, job_received, job_id, job_status_id)
... ON job_status (job_status_id, job_status)
... ON pr_practice (id)
... ON sub_subactivity (sub_Code)
... ON task (job_id, task_id)
... ON task_assign (task_id, assignee_id)
... ON CLIENT (client_id, id, client_name) 

我们确实需要查看EXPLAIN的输出,以了解MySQL是否正在使用这些索引,并且我们需要测试性能。


我们通常会避免使用旧式逗号语法进行连接操作;我们更喜欢使用较新的JOIN关键字语法,并将连接谓词从WHERE子句重定位到适当的ON子句。 。 (逗号语法仍然可用并受支持,但这对于与旧SQL的兼容性非常有用。)


我们可以重新编写查询,保留与原始SQL相同的规范,但这不会改变执行计划,因此不会导致性能上的任何差异:

SELECT DISTINCT j1.job_id
     , j1.job_name
     , j1.client_id
     , j1.job_status_id
     , j1.int_job_status_id
     , j1.job_type_id
     , j1.job_due_date
     , j1.job_received
     , c1.client_name
     , c1.id
     , j1.period
     , j1.notes
     , j1.staff_notes
     , j1.job_genre
     , j1.job_submitted
     , j1.mas_Code
     , DATE_FORMAT(j1.job_completed_date, '%d/%m/%Y') AS completedDate
     , j1.invoiceno
     , j1.is_active
     , p1.name
     , s1.job_status
  FROM job              j1
  JOIN CLIENT           c1 ON c1.client_id     = j1.client_id
  JOIN pr_practice      p1 ON p1.id            = c1.id
  JOIN job_status       s1 ON s1.job_status_id = j1.job_status_id
  JOIN sub_subactivity  sa ON sa.sub_Code      = j1.job_type_id
  JOIN task             t  ON t.job_id         = j1.job_id
  LEFT JOIN task_assign ta ON ta.task_id       = t.task_id
 WHERE j1.discontinue_date IS NULL
   AND j1.job_submitted = 'Y'
   AND j1.job_status_id <> 7
   AND j1.is_active = 1
   AND ( ( j1.job_type_id IN (8,5,6,9,19,19,7,16,17)
         AND (  FIND_IN_SET(134,p1.sr_manager)
             OR FIND_IN_SET(134,p1.manager)
             OR FIND_IN_SET(134,p1.tl1)
             OR FIND_IN_SET(134,p1.tl2)
             OR FIND_IN_SET(134,p1.tl3)
             OR FIND_IN_SET(134,p1.tl4)
             OR FIND_IN_SET(134,p1.sales)
             )
         )
       OR ta.assignee_id IN (134)
       )
 ORDER BY j1.job_received DESC, j1.job_id DESC
 LIMIT 0,25

请注意,由于AND和OR布尔运算符的优先级,OR ta.assignee_id谓词忽略j1.job_type_id上​​的谓词。在重写的查询中添加parens会保留此行为。此外,原始查询的t.job_id = j1.job_id子句中的WHERE谓词有效地否定了&#34;外部性&#34; LEFT JOIN task t操作,使其等同于INNER JOIN