簡體   English   中英

多次連接同一張表時優化Mysql Query

[英]Optimize Mysql Query while joining same table multiple times

Can anybody help me optimize this mysql query?
The query is taking more than 1 min to fetch 1000 rows of data. 
The sub query with FIND_IN_SET(id,GROUP_CONCAT(t.id))!=0 in the select statement is taking too much time to fetch data.

您還可以提供一些技巧來優化查詢,因為我們必須多次連接同一張表。 該查詢在下面提到:

   SELECT mem.id,
    CASE 
    WHEN t.due_date IS NOT NULL THEN
    (SELECT description FROM descriptionTable WHERE CODE=
    (SELECT task_type FROM memberTask WHERE FIND_IN_SET(id,GROUP_CONCAT(t.id))!=0 AND due_date=MIN(t.due_date) LIMIT 1))
    ELSE
    (SELECT description FROM descriptionTable WHERE CODE=
    (SELECT task_type FROM memberTask WHERE FIND_IN_SET(id,GROUP_CONCAT(t1.id))!=0 AND due_date=MIN(t1.due_date) LIMIT 1))
    END AS task_type
    FROM member mem
    INNER JOIN memberProgram p ON mem.id=p.member_id
    LEFT JOIN memberTask t ON t.program=p.prog_name AND t.member_id=p.member_id AND t.status=1
    LEFT JOIN memberTask t1 ON t1.member_id=p.member_id AND t1.status=1 AND t1.program IS NULL 
    GROUP BY mem.id

提前致謝!!!

您使用查詢的方式將增加查詢執行的復雜性,並且必須經過許多交叉連接的行才能提取所需的行。 更好的解決方案將首先從目標表中提取所需的行:memberTask,然后將其連接到主查詢。

SELECT 
REPLACE(GROUP_CONCAT(COALESCE(CASE WHEN t1.program IS NOT NULL THEN t1.id ELSE NULL END,'')),',','') AS first_dueDate,
REPLACE(GROUP_CONCAT(COALESCE(CASE WHEN t1.program IS NOT NULL THEN 'first' ELSE 'second' END,'')),',','') AS selectFlag,
REPLACE(GROUP_CONCAT(COALESCE(CASE WHEN t1.program IS NULL THEN t1.id ELSE NULL END,'')),',','') AS first_dueDate,
aa.member_id FROM memberTask t1
INNER JOIN (SELECT due_date,program,aa.member_id,MAX(tsk.id) AS selId FROM memberTask tsk 
INNER JOIN ( SELECT t.member_id,t.program,t.task_type,MIN(due_date) AS seldate FROM memberTask t WHERE tsk.status=1 
GROUP BY t.member_id,IFNULL(t.program,''))aa 
ON tsk.member_id=aa.member_id AND IFNULL(tsk.program,'')=IFNULL(aa.program,'') AND tsk.due_date=aa.seldate 
GROUP BY due_date,program,aa.member_id) bb ON t1.id=bb.selId GROUP BY t1.member_id,t1.program

該查詢的細分如下:

SELECT t.member_id,t.program,t.task_type,MIN(due_date) AS seldate FROM memberTask t WHERE tsk.status=1 
GROUP BY t.member_id,IFNULL(t.program,'')

這是最內部的查詢,它將根據memberid及其選擇最短到期日期的程序提取記錄。

SELECT due_date,program,aa.member_id,MAX(tsk.id) AS selId FROM memberTask tsk 
INNER JOIN (Inner Most Query)aa 
ON tsk.member_id=aa.member_id AND IFNULL(tsk.program,'')=IFNULL(aa.program,'') AND tsk.due_date=aa.seldate 
GROUP BY due_date,program,aa.member_id

該查詢將在到期日相同的行中提取最大id

SELECT 
REPLACE(GROUP_CONCAT(COALESCE(CASE WHEN t1.program IS NOT NULL THEN t1.id ELSE NULL END,'')),',','') AS first_dueDate,
REPLACE(GROUP_CONCAT(COALESCE(CASE WHEN t1.program IS NOT NULL THEN 'first' ELSE 'second' END,'')),',','') AS selectFlag,
REPLACE(GROUP_CONCAT(COALESCE(CASE WHEN t1.program IS NULL THEN t1.id ELSE NULL END,'')),',','') AS first_dueDate,
aa.member_id FROM memberTask t1
INNER JOIN (second query) bb ON t1.id=bb.selId GROUP BY t1.member_id,t1.program

這會將整個多行數據拉到單行。

現在,在將此選定數據連接到主查詢時,應使用以下情況。

SELECT * FROM member mem
INNER JOIN program pro om mem.id=pro.member_id
LEFT JOIN tmpTable tl ON t1.member_id=mem.member_id AND
CASE WHEN FIND_IN_SET(pro.`prog_name`, t1.prog_relate_task) THEN t1.program=pro.program AND t1.selectFlag='first'
ELSE t1.selectFlag='second' END 

這些是對您的情況的一般理解。 您可以根據需要更改提取記錄

讓我知道它是否有效?

我仍然不確定我是否完全理解查詢應該做什么。 我的理解是:為每個成員獲取任務(無論是否與程序相關)的最小截止日期,並為此獲取任務類型的描述。

因此:選擇成員並使用LIMIT在子查詢中獲取描述:

select
  m.id,
  (
    select d.description
    from membertask t
    join descriptiontable d on d.code = t.task_type
    where t.member_id = m.id
    order by t.due_date
    limit 1
  ) as description
from member;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM