使用从属子查询缓慢MySQL查询(检查客户端的第一个案例)

时间:2013-11-14 23:07:55

标签: mysql sql performance subquery

我有一个SQL查询(MySQL),用于收集由特定推荐公司推荐的客户生成的新案例(作业)的详细信息。重要的是,我们只需要选择那些客户端的第一种情况,否则重复客户端会注册为反复引用,这不是我们想要得到的。在我们的系统中,我们有客户端和案例表,它们通过m:n表连接(实际上只有1:n),因此用于将案例与其相应的客户端相关联。

只有在客户端的第一个案例中返回值的要求才给我带来麻烦。为此,我在WHERE子句中有一个子查询,通过查找该客户端的任何其他案例来检查特定案例是否是客户端的第一个案例。这给出了正确的输出,但是使查询运行得非常慢,我不知道该怎么做,这就是为什么我求助于StackOverflow找到更好的方法。如果我删除该子查询,它会立即运行。我试过改变子查询来检查COUNT(*)= 0而不是NOT EXISTS。我还修改了它来检查任何较小的case_ids,而不是检查早期案例创建的日期。我尝试过调整其他东西,在每种情况下我得到了类似的慢速结果(约45秒对瞬间)。我不知道如何重做事情使它不是一个依赖子查询。我想到的一个替代方案就是在case表中放入一个简单的字段,表示它是否是客户端的第一个案例,但这会带来其他问题,如果可能的话,这不是我想要做的事情。

注意:如果客户有多个案例,我不能排除客户,因为我需要第一个案例。我不能

我打算为你简化查询但后来我意识到我还要弄清楚如何在EXPLAIN结果中修改那些也是如此,所以我没有。我们有一个客户和一个联系人表和联系人是客户的子女,联系人是有案件的人,并且保存了被推荐的价值,但是我们将由客户来确定他们之前是否有案件。< / p>

尝试1:

SELECT c2.case_id AS Case_ID, [other stuff]
FROM client_contact_cases c1 LEFT JOIN cases c2 ON (c1.case_id = c2.case_id)
LEFT JOIN client_contact c3 ON (c1.client_contact_id = c3.client_contact_id) 
WHERE c2.case_created_date > '2013-05-01 00:00:00' AND c2.case_created_date < '2013-10-31 23:59:59' 
AND c3.refer_by = 'Referring Partner #1' 
AND NOT EXISTS (
     SELECT c2_a.case_id FROM client_contact_cases c1_a LEFT JOIN cases c2_a ON (c1_a.case_id = c2_a.case_id) 
     WHERE c1_a.client_id = c1.client_id AND c2_a.case_created_date < c2.case_created_date
     ) 
ORDER BY Case_ID ASC

EXPLAIN结果:

'1', 'PRIMARY', 'c3', 'ALL', 'PRIMARY', NULL, NULL, NULL, '29340', 'Using where; Using     temporary; Using filesort'
'1', 'PRIMARY', 'c1', 'ref',     'client_has_cases_FKIndex1,client_contact_has_cases_FKIndex2',     'client_has_cases_FKIndex1', '4', 'prod1_cases_clients.c3.client_contact_id', '1', 'Using index'
'1', 'PRIMARY', 'c2', 'eq_ref', 'PRIMARY', 'PRIMARY', '4', 'prod1_cases_clients.c1.case_id',     '1', 'Using where'
'2', 'DEPENDENT SUBQUERY', 'c1_a', 'index', 'client_contact_has_cases_FKIndex2', 'client_contact_has_cases_FKIndex2', '4', NULL, '33682', 'Using where; Using index'
'2', 'DEPENDENT SUBQUERY', 'c2_a', 'eq_ref', 'PRIMARY', 'PRIMARY', '4', 'prod1_cases_clients.c1_a.case_id', '1', 'Using where'

如果我将子查询更改为:

,这是EXPLAIN结果
...SELECT c1_a.case_id FROM client_contact_cases c1_a 
     WHERE c1_a.client_id = c1.client_id AND c1_a.case_id < c2.case_id

说明:

'1', 'PRIMARY', 'c3', 'ALL', 'PRIMARY', NULL, NULL, NULL, '29340', 'Using where; Using temporary; Using filesort'
'1', 'PRIMARY', 'c1', 'ref', 'client_contact_has_cases_FKIndex1,client_contact_has_cases_FKIndex2', 'client_contact_has_cases_FKIndex1', '4', 'prod1_cases_clients.c3.client_contact_id', '1', 'Using index'
'1', 'PRIMARY', 'c2', 'eq_ref', 'PRIMARY', 'PRIMARY', '4', 'prod1_cases_clients.c1.case_id',     '1', 'Using where'
'2', 'DEPENDENT SUBQUERY', 'c1_a', 'ALL', 'client_contact_has_cases_FKIndex2', NULL, NULL, NULL, '33682', 'Range checked for each record (index map: 0x4)'

为每条记录检查的范围(索引图:0x4)是什么?一切都应该有一个索引。非常感谢任何帮助!

1 个答案:

答案 0 :(得分:0)

啊哈,我想出了一个子查询,使用它不依赖!我正在检查子查询中客户端第一个案例列表中的case_ids。现在它运行不到半秒钟。我希望在WHERE子句中加入一些内容来减少它。我不能放入日期范围,因为它会阻止查询检查以前的情况并给我稍微多一点的结果,但我后来添加了一个c3_a.refer_by ='引用伙伴#1'。

子查询现在是:

AND c2.case_id IN (
    SELECT MIN(c2_a.case_id)  
    FROM client_contact_cases c1_a LEFT JOIN cases c2_a ON (c1_a.case_id = c2_a.case_id) 
    GROUP BY c1_a.client_id
 )