0

I have this Query that takes at least 1 minute to run. It uses a lot of Left Joins. Is there any way to make it faster ? I'm new to SQL, so help would be appreciated.

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

1 回答 1

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%'无法使用索引

于 2013-06-11T12:00:42.400 回答