我们可以优化这个SQL查询吗?

时间:2013-06-11 11:42:04

标签: mysql performance query-optimization

我有这个查询需要至少1分钟才能运行。它使用了很多左连接。 有没有办法让它更快?我是SQL的新手,所以请帮助。

   SELECT
    distinct cnt.last_name,
    cnt.bus_ph_num,
    cnt.email_addr,
    usr.login,
    cnt.fst_name,
    cnt.fk_id  
from
    contact cnt
LEFT JOIN
    transaction tran 
        ON tran.id=cnt.fk_id    
left join
    party party 
        on party.pk_id=cnt.fk_id  
left join
    user usr 
        on usr.fk_id=cnt.fk_id  
left join
    role role
on      
    usr.role_id = role.pk_row_id
where
    cnt.status_cd=1  
    and   party.fk_id= 'xyz'  
    and (
        usr.login  like '%somevalue%'  
        and  (
            tran.txn_trk_num is  null ||  tran.txn_trk_num like '%somevalue%' 
        ) 
        and  cnt.last_name like '%somevalue%'  
        and  cnt.email_addr like '%somevalue%'  
        and  cnt.busin_ph_num like '%somevalue%'    
    ) 
    and (
        tran.txn_trk_num is  null || tran.txn_typ=1 || tran.txn_typ=2 || tran.txn_typ=3
    ) 
    and (role.role_name ='ROLE_ADMIN')

1 个答案:

答案 0 :(得分:2)

对,我试图尽我所能。主要是一些重新排序,一些交换到INNER JOIN并将WHERE语法移动到连接。一些别名的重命名,因为您使用了与表名匹配的别名,否定了它们的用途。

这将返回没有匹配事务的行,因此您可能希望将该连接更改为INNER,而不是取决于目的/预期输出,但这应该是一个很好的起点。它允许MySQL减少它看到的行数。

可以通过合适的索引进一步改进,但是如果不了解数据类型/数据的差异等,就可以提出建议。

SELECT DISTINCT
    cnt.last_name,
    cnt.bus_ph_num,
    cnt.email_addr,
    u.login,
    cnt.fst_name,
    cnt.fk_id  

FROM contact cnt

-- Changed  to INNER JOIN as the WHERE indicates this is required
INNER JOIN party p 
    ON p.pk_id=cnt.fk_id  
    -- Moved this limiting statement to the join
    AND p.fk_id= 'xyz' 

-- Changed to INNER JOIN as the LIKE % indicates htis is required
INNER JOIN user u 
    ON u.fk_id=cnt.fk_id 
    -- OP added later, quite inefficient due to use of wildcards on both sides causing scans
    AND u.login LIKE '%somevalue%'  

-- Also here, INNER, as the WHERE means this is required
INNER JOIN role r
    ON r.pk_row_id = u.role_id
    -- Moved this limiting statement to the join
    AND r.role_name ='ROLE_ADMIN'

LEFT JOIN transaction tran 
    ON tran.id=cnt.fk_id
    -- Moved this limiting statement to the join
    AND tran.txn_typ IN ( 1 , 2 , 3 )
    -- OP added later, quite inefficient due to use of wildcards on both sides causing scans
    AND tran.txn_trk_num LIKE '%somevalue%' 

WHERE cnt.status_cd = 1  
    -- OP added later, quite inefficient due to use of wildcards on both sides causing scans
    AND cnt.last_name LIKE '%somevalue%'  
    AND cnt.email_addr LIKE '%somevalue%'  
    AND cnt.busin_ph_num LIKE '%somevalue%' 

如果你能摆脱那些LIKE语句,它也会变得更好。如果有合适的索引,以下内容可以使用索引:

  • ... LIKE 'somevalue'
  • ... = 'somevalue'
  • ... LIKE 'somevalue%'

但是... LIKE '%somevalue%'无法使用索引