0

我正在尝试提高此查询的性能,因为它需要 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

4

2 回答 2

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)
    
于 2013-10-29T15:46:58.560 回答
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)索引accounts(对于 client_id = 4 的查询(status, client_id, account_name))和 contact_numbers 中的索引account_id。这应该足够了。

于 2013-10-30T09:22:30.733 回答