【问题标题】:MySQL ORDER BY extremely slow - even with indexesMySQL ORDER BY 非常慢 - 即使有索引
【发布时间】:2013-04-30 08:31:16
【问题描述】:

我有一个非常复杂的查询,其中包含许多连接,无需排序即可运行良好。但是,当我尝试按我的任何字段排序时,它的执行速度非常慢,大约需要 30 秒才能完成。

查询如下:

SELECT SQL_NO_CACHE *
FROM et_order

INNER JOIN et_order_type ON et_order.type_id = et_order_type.id
INNER JOIN et_order_data ON et_order.id = et_order_data.order_id
INNER JOIN et_user et_user_consultant ON et_order.user_id_consulting = et_user_consultant.id
INNER JOIN et_customer ON et_order.customer_id = et_customer.id
INNER JOIN et_appointment ON et_order.appointment_id = et_appointment.id
INNER JOIN et_order_status order_status ON et_order.order_status_id = order_status.id
INNER JOIN et_status glass_r_status ON et_order_data.status_id_glass_r = glass_r_status.id
INNER JOIN et_status glass_l_status ON et_order_data.status_id_glass_l = glass_l_status.id

ORDER BY et_order.id DESC 

LIMIT 50

原来的查询更大,还有各种 WHERE 操作,但即使是没有任何条件的基本查询也慢得不合理。当我删除 ORDER BY et_order.id DESC 时,查询大约需要 0.01 秒才能获取。

在我的原始查询中,我分别选择了我需要的每个字段 - 现在只是将其更改为“SELECT *”以提高语句的可读性。

解释选择给出以下结果:

+----+--------------+--------+--------+ -------------------------------------------------- -----------------------------+-------------+------ ---+--------------------------------------------+---- ---+------------------------------------------------+ |编号 |选择类型 |表|类型 |可能的键 |关键 | key_len |参考 |行 |额外 | +----+--------------+--------+--------+ -------------------------------------------------- -----------------------------+-------------+------ ---+--------------------------------------------+---- ---+------------------------------------------------+ | 1 |简单 | et_customer |全部 |初级 |空 |空 |空 | 59750 |使用临时的;使用文件排序 | | 1 |简单 | et_order |参考 | PRIMARY,customer_id,appointment_id,user_id_consulting,order_status_id,type_id |客户 ID | 4 | eyetool.et_customer.id | 1 | | | 1 |简单 | et_user_consultant | eq_ref |初级 |初级 | 4 | eyetool.et_order.user_id_consulting | 1 | | | 1 |简单 | et_约会 |参考 |初级 |初级 | 8 | eyetool.et_order.appointment_id | 1 | | | 1 |简单 | et_order_data |参考 | status_id_glass_l,status_id_glass_r,order_id | order_id | 5 | eyetool.et_order.id | 1 |使用位置 | | 1 |简单 | et_order_type |全部 |初级 |空 |空 |空 | 4 |使用哪里;使用连接缓冲区 | | 1 |简单 | glass_l_status | eq_ref |初级 |初级 | 4 | eyetool.et_order_data.status_id_glass_l | 1 | | | 1 |简单 |订单状态 | eq_ref |初级,id |初级 | 4 | eyetool.et_order.order_status_id | 1 | | | 1 |简单 | glass_r_status | eq_ref |初级 |初级 | 4 | eyetool.et_order_data.status_id_glass_r | 1 | | +----+--------------+--------+--------+ -------------------------------------------------- -----------------------------+-------------+------ ---+--------------------------------------------+---- ---+------------------------------------------------+ 一组 9 行(0.00 秒)

我真正不明白的是为什么解释选择说它不使用任何键用于 et_order_type。也许是因为它只有 4 行,所以不需要它!?

但是et_order中的type_id上​​有一个索引:KEY type_id (type_id)

我为我用于加入和订购的每个键添加了一个(单个)INDEX。这可能是问题吗?我需要创建组合索引吗?

该表在 et_order 和 et_order_data 中包含大约 200.000 个数据集,在 et_customer 中包含 60.000 个,在 et_apointments 中包含 150.000 个。其他内容可忽略不计。

当我刚刚加入 et_order_data 和 et_order_type 时,它​​也需要很长时间并且解释 select 仍然说 et_order_type 的 key NULL:

解释选择 SQL_NO_CACHE * FROM et_order 内连接 et_order_type on et_order.type_id = et_order_type.id 内连接 et_order_data on et_order.id = et_order_data.order_id ORDER BY et_order.id DESC 限制 50 +----+-------------+---------------+------+------- ----------+----------+----------+------------------ ---+--------+---------------------------------+ |编号 |选择类型 |表|类型 |可能的键 |关键 | key_len |参考 |行 |额外 | +----+-------------+---------------+------+------- ----------+----------+----------+------------------ ---+--------+---------------------------------+ | 1 |简单 | et_order |全部 | PRIMARY,type_id |空 |空 |空 | 162007 |使用临时的;使用文件排序 | | 1 |简单 | et_order_data |参考 | order_id | order_id | 5 | eyetool.et_order.id | 1 |使用位置 | | 1 |简单 | et_order_type |全部 |初级 |空 |空 |空 | 4 |使用哪里;使用连接缓冲区 | +----+-------------+---------------+------+------- ----------+----------+----------+------------------ ---+--------+---------------------------------+

可在此处查看 et_order 和 et_order_type 的表结构http://pastebin.com/PED6Edyx

有什么提示可以优化我的查询吗?

我尝试在子查询中进行排序,例如:

SELECT SQL_NO_CACHE *
FROM (SELECT * FROM et_order ORDER BY et_order.id DESC) as et_order
INNER JOIN et_order_type ON et_order.type_id = et_order_type.id
...

这非常快,但根本没有帮助,因为我不仅要对 et_order 进行排序,还要对连接表的字段进行排序。

提前感谢您的帮助!

更新:

奇怪,当我将每个内部连接更改为左连接时,它就像一个魅力......

选择 SQL_NO_CACHE * FROM et_order 左连接 et_order_type on et_order.type_id = et_order_type.id LEFT JOIN et_order_data ON et_order.id = et_order_data.order_id 左加入 et_user et_user_consultant ON et_order.user_id_consulting = et_user_consultant.id 左加入 et_customer on et_order.customer_id = et_customer.id LEFT JOIN et_appointment ON et_order.appointment_id = et_appointment.id 左加入 et_order_status order_status ON et_order.order_status_id = order_status.id 左加入 et_status glass_r_status ON et_order_data.status_id_glass_r = glass_r_status.id 左加入 et_status glass_l_status on et_order_data.status_id_glass_l = glass_l_status.id

ORDER BY et_order.id DESC LIMIT 50

有人知道为什么吗?

【问题讨论】:

  • 任何时候你在数以万计的行上看到“使用临时;使用文件排序”,你就知道你会有糟糕的一天。
  • 59750 |使用临时的;使用文件排序 --- 这就是杀死它的原因。
  • 您能否在不对结果进行排序的情况下获得所需的数据 - 而是在应用程序级别对数据进行排序?
  • @DudeSolutions 在应用程序级别排序会很多,大约有 200.000 个结果需要排序..
  • @tadman 是的,文件排序很痛苦,但我该如何处理呢?

标签: mysql performance query-optimization innodb


【解决方案1】:

试试这个查询

SELECT SQL_NO_CACHE *
FROM et_order
INNER JOIN et_order_type ON et_order.type_id = et_order_type.id
INNER JOIN et_order_data ON et_order.id = et_order_data.order_id
INNER JOIN et_user et_user_consultant ON et_order.user_id_consulting = et_user_consultant.id
INNER JOIN et_customer FORCE INDEX(et_customer.id) ON et_order.customer_id = et_customer.id
INNER JOIN et_appointment ON et_order.appointment_id = et_appointment.id
INNER JOIN et_order_status order_status ON et_order.order_status_id = order_status.id
INNER JOIN et_status glass_r_status ON et_order_data.status_id_glass_r = glass_r_status.id
INNER JOIN et_status glass_l_status ON et_order_data.status_id_glass_l = glass_l_status.id
ORDER BY et_order.id DESC LIMIT 50

【讨论】:

  • 这会产生一个 sql 错误。当我尝试 SELECT SQL_NO_CACHE * FROM et_order FORCE INDEX (customer_id) INNER JOIN et_order_type ON et_order.type_id = et_order_type.id ...大约需要 120 秒才能完成:-(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-30
相关资源
最近更新 更多