如何优化这个mysql查询(max,replace,left join)?

时间:2016-05-13 09:54:44

标签: mysql optimization


我知道每个人都讨厌提出问题,但我需要你的帮助。 所以 - 这就是代码。它必须获取用户的信息

 select
 c.id,
 c.firstName,
 c.lastName,
 ...
 dt.code as docCode,
 dt.name as docName,
 replace(replace(replace(replace(replace(cc.contact, ' ',''), '(',''), ')', ''), '-', ''), '+', '') as homePhone,
 replace(replace(replace(replace(replace(cc1.contact, ' ',''), '(',''), ')', ''), '-', ''), '+', '') as cellPhone
      from Client c
        left join ClientPolicy p on p.id=(select max(pp.id) 
                                            from ClientPolicy pp 
                                            where 
                                            pp.client_id = c.id 
                                            and pp.deleted = 0)
        left join rbPolicyType pt on pt.id = p.policyType_id
        left join ClientDocument d on d.id =(SELECT MAX(dd.id) 
                                            FROM ClientDocument dd 
                                            WHERE 
                                            dd.client_id = c.id 
                                            and dd.deleted = 0)
        left join rbDocumentType dt on dt.id = d.documentType_id and dt.code IN ('1')
        left join ClientContact cc ON cc.id = (select MAX(ccc.id) 
                                                FROM ClientContact ccc 
                                                where 
                                                ccc.client_id = c.id 
                                                and ccc.deleted = 0 
                                                and ccc.contactType_id = 1)
        left join ClientContact cc1 ON cc1.id = (SELECT MAX(ccc1.id) 
                                                FROM ClientContact ccc1 
                                                WHERE  
                                                ccc1.client_id = c.id 
                                                and ccc1.deleted = 0 
                                                and ccc1.contactType_id = 3)
  where
 c.deleted = 0
 and c.firstName like '%'
 and c.patrName like '%'
 and c.lastName like '%'
 and replace(replace(replace(replace(replace(cc.contact, ' ',''), '(',''), ')', ''), '-', ''), '+', '') like '%521%'
 and replace(replace(replace(replace(replace(cc1.contact, ' ',''), '(',''), ')', ''), '-', ''), '+', '') like '%8905%'

每个%表示用户将在那里插入一些数据,例如like '%8905%

关于INDEX' s 我添加了下面的索引,所以这样,我肯定无法帮助

  INDEX client_insurer (client_id, insurer_id),      
  INDEX policyType_id (policyType_id),
  INDEX Serial_Num (serial, number),

关于replace(replace...
我相信正则表达式会给我少1秒的时间并添加这个 How do you extract a numerical value from a string in a MySQL query?
溶剂化不会减少时间(实际上增加5秒)

我不知道(从wherejoin的mb粘贴条件?)如何让它更快。求你帮帮我。

1 个答案:

答案 0 :(得分:0)

好吧,你没有添加explain,没有关于你的数据的信息,没有表结构,也没有关于(有用的)索引的信息。如果没有这个,优化只是一种有根据的猜测。

但无论如何我都会尝试。

我会尝试一系列子查询,因为你必须通过你的所有数据。

select
 c.id,
 c.firstName,
 c.lastName,
 ...
 dt.code as docCode,
 dt.name as docName,
 cphone1 as as homePhone,
 cphone3 as cellPhone
from

( select *,
  replace(replace(replace(replace(replace(cc.contact, ' ',''), '(',''), ')', ''), '-', ''), '+', '') as cphone1,
  replace(replace(replace(replace(replace(cc1.contact, ' ',''), '(',''), ')', ''), '-', ''), '+', '') as cphone3
  from 
  (select c.id,
    (select max(pp.id) from ClientPolicy pp 
     where pp.client_id = c.id and pp.deleted = 0) as pmax,
    (select max(dd.id) FROM ClientDocument dd 
     WHERE dd.client_id = c.id and dd.deleted = 0) as dmax,
    (select MAX(ccc.id) FROM ClientContact ccc 
     where ccc.client_id = c.id and ccc.deleted = 0 
     and ccc.contactType_id = 1) as cmax1,
    (SELECT MAX(ccc1.id) FROM ClientContact ccc1 
     WHERE ccc1.client_id = c.id and ccc1.deleted = 0 
     and ccc1.contactType_id = 3) as cmax3
    from Client c        
    where c.deleted = 0
     and c.firstName like '%'
     and c.patrName like '%'
     and c.lastName like '%'
  ) as clientbase
  join ClientContact cc on cc.id = clientbase.cmax1
  join ClientContact cc1 on cc1.id = clientbase.cmax3
) as clientnamed
join client c on c.id = clientnamed.id
left join ClientPolicy p on p.id=clientnamed.pmax
left join rbPolicyType pt on pt.id = p.policyType_id
left join ClientDocument d on d.id = clientnamed.dmax
left join rbDocumentType dt on dt.id = d.documentType_id and dt.code = 1
where cphone1 like '%521%' and cphone3 like '%8905%';

如果您的搜索参数'%521%'或'%8905%'是可选的(例如并非总是给定),则必须使用left join ClientContact cc(对于cc1相同),但是没有{{1在cphone1 like '%521%' {同一where)中,因为它会再次充当cphone3 like '%8905%'。 (而你的join实际上也不应该在那里。)

如果您能够在新列中以干净的方式使用电话号码(例如,通过触发器更新),您可能会得到改进。

现在索引:

您必须将like '%'作为主键。

为Client(id,deleted),ClientPolicy(id,deleted)和ClientDocument(id,deleted)创建索引。

你应该在ClientContact上尝试索引(id,删除,contact_type)或(id,contact_type,删除) - 取决于你的数据:如果你有很多删除的条目,第一个应该更好,否则秒

如果这些索引具有可衡量的效果取决于您的数据,但由于您没有告诉我们有关您的数据的任何信息,请尝试它(拥有大量索引会降低您的插入/更新速度,所以不要垃圾邮件索引;但是,你没有告诉我们关于数据的任何信息,所以你必须自己试一试。)

对于任何后续操作,您必须至少添加以下内容

  • id看看mysql究竟在做什么
  • explain表示没有周围代码的子查询explain
  • 获取整个代码和上述子查询的结果所需的时间