我正在尝试提高此查询的性能,因为它需要3-4秒才能执行。 这是查询
SELECT SQL_NO_CACHE
ac.account_id,
ac.account_name,
cl.name AS client_name,
IFNULL(cn.contact_number, "") AS Phone
FROM accounts AS ac
STRAIGHT_JOIN clients AS cl ON cl.client_id = ac.client_id
LEFT JOIN (
SELECT bc.contact_number, bc.account_id
FROM contact_numbers AS bc
INNER JOIN (
SELECT account_id, MAX(number_id) AS number_id
FROM contact_numbers
WHERE status = 1 AND contact_type != "Fax" AND contact_link = "Account"
GROUP BY account_id
) AS bb ON bb.number_id = bc.number_id
) AS cn ON ac.account_id = cn.account_id
WHERE ac.status = 1
ORDER BY ac.account_name
LIMIT 0, 100
客户端表包含大约10行,这就是我直接加入的原因。帐户表包含350K记录。 contact_numbers包含大约500k条记录 我相信这里的问题是左连接和ORDER BY,但我不知道如何解决它。我也在使用SQL_NO_CACHE,因为帐户,contact_numbers表正在快速更新。
我还可以做些什么来改善此查询的效果?
这是此查询解释的屏幕截图
我正在使用MySQL 5.6.13 我设置sort_buffer_size = 1M 我的服务器有32GB的RAM
答案 0 :(得分:0)
以下内容应该使外部查询运行而不需要文件排序。
CREATE INDEX ac_status_acctname ON accounts (status, account_name);
下面应该创建内部查询Using index
,并帮助它在不使用临时表的情况下执行GROUP。
CREATE INDEX cn_max ON contact_numbers (account_id, status, contact_link,
contact_type, number_id);
您需要加入account_id和number_id才能获得每个帐户最大的条目。你现在拥有它的方式,你只是得到任何帐户恰好具有相同的number_id,这可能不是你想要的,它可能是为子查询结果集生成太多行。
bc INNER JOIN ... bb ON bb.account_id = bc.account_id AND bb.number_id = bc.number_id
您也可以将相同的连接条件写为:
bc INNER JOIN ... bb USING (account_id, number_id)
答案 1 :(得分:0)
我会实际重写查询。您当前选择了许多不需要的数据并将其丢弃。我会尽量减少获取数据的数量。
您似乎基本上为具有特定状态的每个帐户选择了一些内容,并且只占用了其中的100个。所以我会把它放在一个子查询中:
SELECT
account_id,
account_name,
c.name AS client_name,
IFNULL(contact_number, '') as Phone
FROM (
SELECT
account_id,
MAX(number_id) as number_id
FROM (
SELECT account_id
FROM accounts
WHERE status = 1 -- other conditions on accounts go here
ORDER BY account_name
LIMIT 0, 100) as a
LEFT JOIN contact_numbers n
ON a.coount_id = n.account_id
AND n.status = 1
AND contact_type != "Fax"
AND contact_link = "Account"
GROUP BY account_id) an
LEFT JOIN contact_numbers USING (account_id, number_id)
JOIN accounts a USING (account_id)
JOIN clients c USING (client_id);
(status, account_name)
表(对于client_id = 4 accounts
的查询)和contact_numbers中(status, client_id, account_name)
的索引需要account_id
索引。这应该足够了。