多次加入同一个表时优化Mysql查询

时间:2017-10-26 10:01:06

标签: mysql sql

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

提前致谢!!!

2 个答案:

答案 0 :(得分:3)

使用查询的方式会增加查询执行的复杂性,并且必须经过许多交叉连接的行来提取所需的行。更好的解决方案是首先从目标表中提取所需的行:memberTask,然后将其连接到主查询。

recyclerView.setRecyclerListener(new RecyclerView.RecyclerListener() {
    @Override
    public void onViewRecycled(RecyclerView.ViewHolder holder) {
        Log.d("onViewRecycled", "recycled------->" + holder);
    }
});

查询细分如下:

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

这是最内部的查询,它将根据memberid及其程序选择最小截止日期来提取记录。

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,'')

此查询将在具有相同截止日期的行中拉出最大ID

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

这会将多行数据整数拉到单行。

现在,在将所选数据加入主查询时,您应该使用以下案例。

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

这些是对您案件的一般理解。您可以根据您的要求更改提取记录

让我知道它是否有效?

答案 1 :(得分:0)

我仍然不确定我是否完全理解查询应该做什么。我理解的是:对于每个成员,使用最小化截止日期获取任务(无论是否与程序相关),并为此获取任务类型的描述。

所以:选择成员并在带有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;