优化在order by子句中使用concat的慢查询

时间:2013-05-04 02:06:48

标签: mysql sql ruby-on-rails

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

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子句中删除第一个AND last以获得任何性能增益。我考虑过的一个选项是在organization.name字段中“缓存”用户名/姓。但是,仅使用organizations.name运行查询排序也不具备性能。而且我必须重构我的应用程序代码。
  2. 删除order_details表的所有引用,包含(this 实际上是我们最大的表,约101K记录)。但是我没有订单详细信息的总和,而且我没有将结果限制为那些带有>的order_headers。 0
  3. 非常感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

首先,您有一个似乎没必要的条件ORDER BY子句。 JOIN user_accounts organizations仅指定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

其次,确保在所有外键(您正在加入的外键)上设置索引,并且可能在{{1}}上设置索引以帮助进行排序。