我正在调试一个耗时过多的 MYSQL 查询。
查询是这样的:
SELECT *, TM.tutor_id as tutor_id,
TIMESTAMPDIFF( YEAR, birthdate, CURDATE( ) ) AS age
FROM tutor_master as TM
LEFT JOIN category_master as CM on CM.category_id=TM.category
LEFT JOIN tutor_expected_rate TER ON FIND_IN_SET(TER.tutor_id, TM.tutor_id) > 0
LEFT JOIN admin_shortlist_master SHM ON TM.tutor_id = SHM.tutor_id
AND (SHM.user_auth_id = 'c84258e9c39059a89ab77d846ddab909')
LEFT JOIN level_master LM ON FIND_IN_SET(LM.level_id, TER.level_id) > 0
WHERE 1=1
GROUP BY TM.tutor_id
order by TM.is_priority DESC, TM.tutor_id DESC LIMIT 0, 10
如果我排除部分
WHERE 1=1
GROUP BY TM.tutor_id
ORDER BY TM.is_priority DESC, TM.tutor_id DESC LIMIT 0, 10
查询是这样执行的:
Showing rows 0 - 29 ( 27,649 total, Query took 0.2339 sec)
完整查询是这样的:
Showing rows 0 - 9 ( 10 total, Query took 115.4066 sec)
我已经为查询中使用的所有字段编制了索引。
MYSQL的解释是这样的:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE TM ALL NULL NULL NULL NULL 27530 Using temporary; Using filesort
1 SIMPLE CM eq_ref PRIMARY PRIMARY 4 toprecru_portal_db.TM.category 1
1 SIMPLE TER ALL NULL NULL NULL NULL 13223
1 SIMPLE SHM ref tutor_id,user_auth_id user_auth_id 257 const 1
1 SIMPLE LM ALL NULL NULL NULL NULL 11
更新:
我在某处读到使用 1=1 不会对性能产生影响,但即使添加 1=1 查询也需要从 0.2339 秒开始大约 70 秒。
MYSQL my.cnf设置是这样的:
read_buffer_size = 512M
join_buffer_size = 512M
sort_buffer_size = 256M
更新:
在不使用 order_by 的情况下使用 group_by 时,时间几乎相同:
Showing rows 0 - 29 ( 27,530 total, Query took 114.9642 sec)
更新样本日期: 表 - 导师期望率
id tutor_id level_id exp_rate
1 27597 4 $30-35/hr
2 27597 10 $40-45/hr
99 27598 5 35-40/hr minimum
124 27602 4 25-30/hr or 30-40/hr minimum 1.5hrs per session
125 27602 0
表 - admin_shortlist_master
admin_shortlist_id job_ad_id request_profile_id tutor_id user_auth_id added_date
143693 0 0 22692 4ef44ea2203114a3e27eaff31a1bf3be 2015-09-17
143694 0 0 11653 4ef44ea2203114a3e27eaff31a1bf3be 2015-09-17
143695 0 0 27611 4ef44ea2203114a3e27eaff31a1bf3be 2015-09-17
143696 0 0 27610 4ef44ea2203114a3e27eaff31a1bf3be 2015-09-17
296793 0 13 0 21232f297a57a5a743894a0e4a801fc3 2015-10-05
表格-类别大师
category_id category_name disp_order status 0-Not Published, 1-Published
1 Polytechnic Student 0 1
2 Diploma Grad Part Time 1 1
3 Diploma Grad Full Time 2 1
4 JC Student 3 0
5 A Level Grad Part Time 4 1
表级大师
level_id level_name class_title class_ids subject_ids status 0-Not Published, 1-Published
4 Primary Primary 4,5,6,7,8,9,10 5,6,7,8,9,10,11,12,14,15 1
5 O Level (Secondary) Secondary 12,13,14,15,16
4,5,6,7,8,9,10,13,14,15,16,17,18,19,20,21,22,23,24... 1
6 A Level (JC) JC 18,19,20 6,17,18,19,23,24,25,26,30,31,32,33,34,35,36,37,38,... 1
7 International Baccalaureate 17,18,19,23,24,34,40,41,42,43,44,45,46,47,48,49,50... 1
8 Diploma 26,34,47,54,55,56,57,59,60,61,62,63,64,65,66,67,68... 1
更新:
select tutor_id, category, is_priority, birthdate from tutor_master order by tutor_id limit 5
tutor_id Ascending 1 category is_priority birthdate
4 8 0 1989-01-01
7 8 0 1987-01-01
8 8 0 1964-01-01
9 2 0 1987-01-01
10 8 0 1983-01-01
最佳答案
在不知道表结构和一些样本数据的情况下调试起来有点困难(如果您可以编辑原始问题以包含这些数据会有所帮助)。看来您最大的问题是所有表上都没有标记。
您应该能够得到这样的输出,其中所有内容都使用索引:
+------+-------------+-------+--------+---------------+----------+---------+--------------------------+------+--------------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+--------+---------------+----------+---------+--------------------------+------+--------------------------------------------------------------+
| 1 | SIMPLE | TM | ALL | NULL | NULL | NULL | NULL | 2 | Using temporary; Using filesort |
| 1 | SIMPLE | CM | eq_ref | PRIMARY | PRIMARY | 4 | tutors.TM.category | 1 | Using index |
| 1 | SIMPLE | TER | index | NULL | tutor_id | 8 | NULL | 1 | Using where; Using index; Using join buffer (flat, BNL join) |
| 1 | SIMPLE | SHM | eq_ref | tutor_id | tutor_id | 606 | tutors.TM.tutor_id,const | 1 | Using where; Using index |
| 1 | SIMPLE | LM | index | NULL | PRIMARY | 4 | NULL | 1 | Using where; Using index; Using join buffer (flat, BNL join) |
+------+-------------+-------+--------+---------------+----------+---------+--------------------------+------+--------------------------------------------------------------+
因为您正在使用 FIND_IN_SET
,您可能无法删除连接缓冲区,而且它似乎总是需要对导师进行全表扫描,这应该不是问题。
这些是我对所有表格的标记:
MariaDB [tutors]> show indexes from admin_shortlist_master;
+------------------------+------------+----------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+------------------------+------------+----------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| admin_shortlist_master | 0 | PRIMARY | 1 | id | A | 0 | NULL | NULL | | BTREE | | |
| admin_shortlist_master | 0 | tutor_id | 1 | tutor_id | A | 0 | NULL | NULL | | BTREE | | |
| admin_shortlist_master | 0 | tutor_id | 2 | user_auth_id | A | 0 | NULL | NULL | | BTREE | | |
+------------------------+------------+----------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.00 sec)
MariaDB [tutors]> show indexes from category_master;
+-----------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| category_master | 0 | PRIMARY | 1 | category_id | A | 0 | NULL | NULL | | BTREE | | |
+-----------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)
MariaDB [tutors]> show indexes from level_master;
+--------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+--------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| level_master | 0 | PRIMARY | 1 | level_id | A | 0 | NULL | NULL | | BTREE | | |
+--------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)
MariaDB [tutors]> show indexes from tutor_expected_rate;
+---------------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| tutor_expected_rate | 0 | PRIMARY | 1 | id | A | 0 | NULL | NULL | | BTREE | | |
| tutor_expected_rate | 0 | tutor_id | 1 | tutor_id | A | 0 | NULL | NULL | | BTREE | | |
| tutor_expected_rate | 0 | tutor_id | 2 | level_id | A | 0 | NULL | NULL | | BTREE | | |
+---------------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.00 sec)
如果您想提供您的整体结构和一些样本数据,那么可能还有一种方法可以索引 tutor_master
表,但目前很难确定。
关于php - MYSQL 查询在使用 where、group by 和 order by 时花费太多时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44478211/