2014-02-11 78 views
0

我有下面的查询,我试图改写它来改善性能,我可以用什么方法来重写它。如何重写MySQL查询

select 
    notes.id, notes.name, notes.parent_type, notes.contact_id from notes 
JOIN 
    ( 
    SELECT contact_id as id from accounts_contacts where account_id = 'acct1876' and deleted = '0' union 
    SELECT quote_id as id from quotes_accounts where account_id = 'acct1876' and deleted = '0' union 
    SELECT opportunity_id as id from accounts_opportunities where account_id = 'acct1876' and deleted = '0' union 
    SELECT leads.id as id from leads where account_id = 'acct1876' and deleted = '0' union 
    SELECT project_id as id from projects_accounts where account_id = 'acct1876' and deleted = '0' union 
    select 'acct1876' as id 
    ) A 
    ON A.id = notes.parent_id and deleted = '0' OR contact_id in 
    (SELECT contact_id from accounts_contacts where account_id = 'acct1876' and deleted = '0') and deleted = '0' 

    group by notes.id; 
+0

你可以学习JOIN,但是你真的不知道你在这里做什么!?!?! – Strawberry

+3

如果你能解释你的需求,而不是希望人们能正确地从你的查询中反向工程,那将会有很大帮助。另外,您滥用“GROUP BY”;在查询中没有聚合函数(如'SUM()'或'GROUP_CONCAT()')。 –

+0

基本上查询很慢。索引是确定的,但总体表现并不理想。我正在尝试重新构造查询以生成相同的输出。 –

回答

0

要回答您的问题并提升性能,我想建议一种看起来很奇怪的方法。

如果您有合理数量的记录,请使用更多选择,而不是单个(而且重)。你可以在数组中收集ID,或者(最好)在字符串中收集ID,然后用逗号等分隔ID列表来查询另一个查询。虽然这听起来完全是无稽之谈,但它几乎没有缺点:单独的SELECT运行速度很快,然后让数据库服务器呼吸。当你做一个SELECT时,其他表不会被锁定(!!!),而一个大的选择将锁定整个查询所涉及的所有表。所以它更容易和更具可读性做到这一点:

$idlist = fetch_idlist("select id from users where name like 'John%'"); 
$result = fetch_all("select * from mails where userid in ($idlist)"); 

比这

$result = fetch_all("select * from mails left join users on users.id=mails.userid ....") 

我希望意思是尽管不存在的功能明确。这只是原则。所以在你的情况下,也许你想选择联系人,建立id列表,然后为笔记等做单独的查询,并在php中编写最终结果。

再一次,这只适用于百万以下的记录数量,你不能吃掉所有内存的数量非常高。但重点是:在高负载情况下,对于费时的查询要分开进行,让其他进程适合其间,而不是在相对较长的时间内锁定大量表。

对不起,如果它不是100%的答案,但我认为这是值得解释。

1

首先,你的最终OR是你的内部连接开始的重复,否则就毫无意义。

这部分

ON A.id = notes.parent_id 
    and deleted = '0' 
    OR contact_id in (SELECT contact_id 
         from accounts_contacts 
         where account_id = 'acct1876' 
         and deleted = '0') 
    and deleted = '0' 

可以只是

ON A.id = notes.parent_id 

接下来,您似乎在试图让与给定帐户相关联的所有标识,包括有问题的帐户。我会确保这些表中的每一个在帐户ID和已删除列上都有一个索引。此外,对于这个查询,我将它作为DISTINCT来防止重复被加入到笔记表中。然后,我会交换订单(对我来说,精神上查询你想要的ID,然后让笔记关联)。下面介绍了UNION查询的每个表的索引,以及连接的父ID号列中的注释表。

table     index 
accounts_contacts  (account_id, deleted, contact_id) 
quotes_accounts  (account_id, deleted, quote_id) 
accounts_opportunities (account_id, deleted, opportunity_id) 
leads     (account_id, deleted, id 
projects_accounts  (account_id, deleted, project_id) 
notes     (parent_id) 

现在,次要更新的查询

select 
     notes.id, 
     notes.name, 
     notes.parent_type, 
     notes.contact_id 
    from 
     (SELECT DISTINCT contact_id as id 
      from accounts_contacts 
      where account_id = 'acct1876' and deleted = '0' 
      union 
      SELECT quote_id as id 
      from quotes_accounts 
      where account_id = 'acct1876' and deleted = '0' 
      union 
      SELECT opportunity_id as id 
      from accounts_opportunities 
      where account_id = 'acct1876' and deleted = '0' 
      union 
      SELECT leads.id as id 
      from leads 
      where account_id = 'acct1876' and deleted = '0' 
      union 
      SELECT project_id as id 
      from projects_accounts 
      where account_id = 'acct1876' and deleted = '0' 
      union 
      select 'acct1876' as id) A 
     JOIN Notes 
      ON A.id = notes.parent_id 
    group by 
    notes.id; 

正如有人所说,你有一组,但发现这样的,这将导致中的第一项列任何款项或聚集成包括在内,并且由于出现了自动递增的ID列,因此无论帐户“ID”源自何处,都将具有相同的值。