4

我有一个非常复杂的查询,其中包含许多连接,无需排序即可运行得很好。但是,一旦我尝试按我的任何字段进行排序,它的执行速度就会非常慢,大约需要 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_idtype_id

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

该表在 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 上进行排序,还要在连接表的字段上进行排序。

在此先感谢您的帮助!

更新:

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

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.在 et_order.appointment_id = et_appointment.id 上左加入 et_appointment

ORDER BY et_order.id DESC LIMIT 50

有谁知道为什么?

4

1 回答 1

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
于 2013-05-07T13:04:07.657 回答