我有一个非常复杂的查询,有许多连接,运行良好而无需订购。但是一旦我尝试通过我的任何字段进行排序,它执行速度非常慢,大约需要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_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说明了键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
有谁知道为什么?
答案 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