【问题标题】:MYSQL Query takes too much time when using where, group by and order byMYSQL Query 在使用 where、group by 和 order by 时花费太多时间
【发布时间】:2017-06-10 21:23:31
【问题描述】:

我正在调试一个耗时太多的 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

查询是这样执行的:

显示第 0 - 29 行(总共 27,649 行,查询耗时 0.2339 秒)

对于完整查询,它是这样的:

显示第 0 - 9 行(共 10 行,查询耗时 115.4066 秒)

我已经为查询中使用的所有字段编制了索引。

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

更新:

当使用 group_by 而没有 order_by 时,时间几乎是一样的:

显示第 0 - 29 行(总共 27,530 行,查询耗时 114.9642 秒)

更新样本日期: 表 - 导师期望率

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  

table-category master

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

【问题讨论】:

  • @Bamar - 实际上我正在调试别人的查询。我想知道为什么要这样使用它,因为在那些列中没有逗号分隔的值。但是话虽如此,即使我不使用 where、group by 和 order by 时使用它,速度也相当不错。
  • 这就是我删除评论的原因,我之前没有看到问题的那部分。
  • 如果你只使用GROUP BY 而不使用ORDER BY 会发生什么?
  • @Barmar - 更新您的查询问题。
  • @Pawan 我也想知道你为什么使用GROUP BY,因为你没有像SUM()COUNT() 这样的聚合函数。

标签: php mysql


【解决方案1】:

在不了解表结构和一些示例数据的情况下很难进行调试(如果您可以编辑原始问题以包含这些数据,那会有所帮助)。看来您最大的问题是所有表格都缺少索引。

您应该能够在所有内容都使用索引的情况下获得这样的输出:

+------+-------------+-------+--------+---------------+----------+---------+--------------------------+------+--------------------------------------------------------------+
| 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 表,但目前很难确定。

【讨论】:

  • 没有tutor_master 的数据,这是唯一有问题的表
  • 那个表tutor_master在这里很难重现,它包含大约150个字段。
  • 那么提供的索引可能是最有效的,因为它使查询中的每个表都使用索引。
  • 我不知道,但是tutor_idlevel_id 上的tutor_expected_rate 上的索引不存在。我已经添加了。如果我将部分LEFT JOIN tutor_expected_rate TER ON FIND_IN_SET(TER.tutor_id, TM.tutor_id) > 0 更改为LEFT JOIN tutor_expected_rate TER ON TER.tutor_id= TM.tutor_id,它会大大加快查询速度。我看不到结果集有任何明显的变化。你能看看它是否可以改变结果集的变化。
  • 如果没有这些更改,它仍然需要 120 秒,但有了这些更改,它会减少到 2 秒以下。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-07
  • 1970-01-01
  • 2020-01-31
  • 2021-02-22
  • 1970-01-01
相关资源
最近更新 更多