我有以下查询,我正在尝试重写它以提高性能,我可以使用什么方法来重写它。
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 :(得分: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,包括相关帐户。我会确保每个表都有一个关于帐户ID和已删除列的索引。此外,对于此查询,我将它作为DISTINCT以防止重复项连接到notes表。然后我会交换订单(对我来说,在心理上查询你想要的ID,然后获得相关的注释)。下面是UNION查询的每个表的索引,以及加入的父ID列的notes表。
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”来自何处,都具有相同的价值。
答案 1 :(得分:0)
为了回答你的问题并提升表现,我想建议一种看似奇怪的方法。
如果您有合理数量的记录,请使用MORE SELECTS,而不是单个(和重)记录。您可以在数组中收集ID,或者(最好)在字符串中收集ID,然后使用逗号等分隔ID列表进行另一个查询。这(虽然听起来完全是胡说八道)有许多优点,几乎没有任何缺点:单独的SELECT运行速度快,然后让数据库服务器呼吸。当您执行一个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%的答案,但我认为值得解释。