0

我在执行多个连接的查询时遇到困难,并且对于大型记录集来说非常慢。这是查询:

SELECT 
    order_headers.*,
    SUM(order_details.cost) AS amount,
    CONCAT(organizations.card_first_name,
            ' ',
            organizations.card_last_name) AS card_name
FROM
    order_headers
        INNER JOIN
    organizations ON order_headers.organization_id = organizations.id
        LEFT JOIN
    order_details ON order_details.order_header_id = order_headers.id
        LEFT JOIN
    user_accounts ON user_accounts.organization_id = organizations.id
        AND organizations.is_single_user = 1
WHERE
    (status IN ('UNCHARGED' , 'ERROR'))
GROUP BY order_headers.id
HAVING SUM(order_details.cost) > 0
ORDER BY IF(organizations.is_single_user = 1,
    (user_accounts.first_name + ' ' + user_accounts.last_name),
    organizations.name) ASC
LIMIT 100 OFFSET 0

我可以从查询中删除一些内容(尽管我的应用程序需要这些内容才能运行),从而将查询速度提高到 ~0.183 秒。其中包括:

  1. 完全删除 order by 子句。出于某种原因,MySQL 不喜欢从 user_accounts 表中提取字段。但这意味着我不能按名字/姓氏排序。仅删除串联是不够的,我必须从 order 子句中删除 first AND last 以获得任何性能提升。我考虑过的一个选项是在 organizations.name 字段中“缓存”用户的名字/姓氏。但是,仅按 organizations.name 运行查询排序也是不合格的。而且我必须重构我的应用程序代码。
  2. 删除 order_details 表的所有引用和包含项(这实际上是我们最大的表,大约有 101K 条记录)。但是我没有订单详细信息的总和,并且我不会将结果限制为 sum > 0 的那些 order_headers。

任何帮助深表感谢。

4

1 回答 1

0

首先,您有一个ORDER BY似乎没有必要的条件子句。您的JOINonuser_accounts仅指定organizationswhere is_single_user = 1。但是您将其用作ORDER BY条件的一部分。is_single_user = 1在这种情况下将永远是真的。

所以试试这个修改ORDER BY后的条款:

SELECT 
    order_headers.*,
    SUM(order_details.cost) AS amount,
    CONCAT(organizations.card_first_name,
            ' ',
            organizations.card_last_name) AS card_name
FROM
    order_headers
        INNER JOIN
    organizations ON order_headers.organization_id = organizations.id
        LEFT JOIN
    order_details ON order_details.order_header_id = order_headers.id
        LEFT JOIN
    user_accounts ON user_accounts.organization_id = organizations.id
        AND organizations.is_single_user = 1
WHERE
    (status IN ('UNCHARGED' , 'ERROR'))
GROUP BY order_headers.id
HAVING SUM(order_details.cost) > 0
ORDER BY user_accounts.first_name, user_accounts.last_name
LIMIT 100 OFFSET 0

其次,确保您在所有外键(您要加入的外键)上设置了索引,并且可能user_accounts.first_name + user_accounts.last_name有助于排序。

于 2013-05-04T04:25:41.197 回答