MySQL ORDER BY非常慢 - 即使有索引

时间:2013-05-06 14:45:06

标签: mysql performance query-optimization innodb

我有一个非常复杂的查询,有许多连接,运行良好而无需订购。但是一旦我尝试通过我的任何字段进行排序,它执行速度非常慢,大约需要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 *”以便更好地阅读该语句。

说明选择会产生以下结果:

+----+-------------+--------------------+--------+-------------------------------------------------------------------------------+-------------+---------+-----------------------------------------+-------+---------------------------------+
| id | select_type | table              | type   | possible_keys                                                                 | key         | key_len | ref                                     | rows  | Extra                           |
+----+-------------+--------------------+--------+-------------------------------------------------------------------------------+-------------+---------+-----------------------------------------+-------+---------------------------------+
|  1 | SIMPLE      | et_customer        | ALL    | PRIMARY                                                                       | NULL        | NULL    | NULL                                    | 59750 | Using temporary; Using filesort |
|  1 | SIMPLE      | et_order           | ref    | PRIMARY,customer_id,appointment_id,user_id_consulting,order_status_id,type_id | customer_id | 4       | eyetool.et_customer.id                  |     1 |                                 |
|  1 | SIMPLE      | et_user_consultant | eq_ref | PRIMARY                                                                       | PRIMARY     | 4       | eyetool.et_order.user_id_consulting     |     1 |                                 |
|  1 | SIMPLE      | et_appointment     | ref    | PRIMARY                                                                       | PRIMARY     | 8       | eyetool.et_order.appointment_id         |     1 |                                 |
|  1 | SIMPLE      | et_order_data      | ref    | status_id_glass_l,status_id_glass_r,order_id                                  | order_id    | 5       | eyetool.et_order.id                     |     1 | Using where                     |
|  1 | SIMPLE      | et_order_type      | ALL    | PRIMARY                                                                       | NULL        | NULL    | NULL                                    |     4 | Using where; Using join buffer  |
|  1 | SIMPLE      | glass_l_status     | eq_ref | PRIMARY                                                                       | PRIMARY     | 4       | eyetool.et_order_data.status_id_glass_l |     1 |                                 |
|  1 | SIMPLE      | order_status       | eq_ref | PRIMARY,id                                                                    | PRIMARY     | 4       | eyetool.et_order.order_status_id        |     1 |                                 |
|  1 | SIMPLE      | glass_r_status     | eq_ref | PRIMARY                                                                       | PRIMARY     | 4       | eyetool.et_order_data.status_id_glass_r |     1 |                                 |
+----+-------------+--------------------+--------+-------------------------------------------------------------------------------+-------------+---------+-----------------------------------------+-------+---------------------------------+
9 rows in set (0.00 sec)

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

但是et_order中有一个关于type_id的索引:KEY type_idtype_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说明了键NULL:

EXPLAIN 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

ORDER BY et_order.id DESC 

LIMIT 50

+----+-------------+---------------+------+-----------------+----------+---------+---------------------+--------+---------------------------------+
| id | select_type | table         | type | possible_keys   | key      | key_len | ref                 | rows   | Extra                           |
+----+-------------+---------------+------+-----------------+----------+---------+---------------------+--------+---------------------------------+
|  1 | SIMPLE      | et_order      | ALL  | PRIMARY,type_id | NULL     | NULL    | NULL                | 162007 | Using temporary; Using filesort |
|  1 | SIMPLE      | et_order_data | ref  | order_id        | order_id | 5       | eyetool.et_order.id |      1 | Using where                     |
|  1 | SIMPLE      | et_order_type | ALL  | PRIMARY         | NULL     | NULL    | NULL                |      4 | Using where; Using join buffer  |
+----+-------------+---------------+------+-----------------+----------+---------+---------------------+--------+---------------------------------+

可以在此处查看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上进行排序,还要对连接表的字段进行排序。

提前感谢您的帮助!

更新

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

SELECT SQL_NO_CACHE * FROM et_order LEFT JOIN 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 LEFT JOIN et_user et_user_consultant ON et_order.user_id_consulting = et_user_consultant.id LEFT JOIN et_customer ON et_order.customer_id = et_customer.id LEFT JOIN et_appointment ON et_order.appointment_id = et_appointment.id LEFT JOIN et_order_status order_status ON et_order.order_status_id = order_status.id LEFT JOIN et_status glass_r_status ON et_order_data.status_id_glass_r = glass_r_status.id LEFT 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

有谁知道为什么?

1 个答案:

答案 0 :(得分:0)

尝试此查询

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