MySQL 查询耗时超过 15 分钟,似乎没有那么多数据

MySQL query takes over 15 minutes, doesn't seem like its THAT much data

所以,这是我的查询:

SELECT content FROM buttons WHERE qid_id in
  (SELECT distinct qid_id FROM groups_qids WHERE group_id IN
    (SELECT 5 
     UNION
     SELECT id FROM groups WHERE parent_id=5
     UNION
     SELECT id FROM groups WHERE parent_id IN 
       (SELECT id FROM groups WHERE parent_id=5)))
  button_type_id=8;

基本上,有一个叫做组的table,我想找到2级以内指向group_id=5的所有组作为其父组。这些组与 qids table 到 groups_qids 相关联,因此我想找到与我刚刚找到的所有这些组相关联的所有 qids。

然后,我们有指向 qid 的按钮,所以我想在上面计算的列表中找到所有 qid 指向 qid 的按钮。

令人惊讶的是子查询:

select distinct qid_id from groups_qids where group_id in 
    (select 5 
     union 
     select id from groups where parent_id=5 
     union 
     select id from groups where parent_id 
       in (select id from groups where parent_id=5));

-- 将在 0.37 秒内 运行,return 生成 10547 行。

按钮 table 中有 99770 行。

此外,这里是 EXPLAIN 的输出:

mysql> explain select content from buttons where qid_id in (select distinct qid_id from groups_qids where group_id in (select 5 union select id from groups where parent_id=5 union select id from groups where parent_id in (select id from groups where parent_id=5))) and button_type_id=8;
+----+--------------------+--------------+-----------------+---------------+---------+---------+------+-------+------------------------------+
| id | select_type        | table        | type            | possible_keys | key     | key_len | ref  | rows  | Extra                            |
+----+--------------------+--------------+-----------------+---------------+---------+---------+------+-------+------------------------------+
|  1 | PRIMARY            | buttons      | ALL             | NULL          | NULL    | NULL    | NULL | 91710 | Using where                  |
|  2 | DEPENDENT SUBQUERY | groups_qids  | ALL             | NULL          | NULL    | NULL    | NULL | 11133 | Using where; Using temporary |
|  3 | DEPENDENT SUBQUERY | NULL         | NULL            | NULL          | NULL    | NULL    | NULL |  NULL | No tables used               |
|  4 | DEPENDENT UNION    | groups       | eq_ref          | PRIMARY       | PRIMARY | 4       | func |     1 | Using where                  |
|  5 | DEPENDENT UNION    | groups       | eq_ref          | PRIMARY       | PRIMARY | 4       | func |     1 | Using where                  |
|  6 | DEPENDENT SUBQUERY | groups       | unique_subquery | PRIMARY       | PRIMARY | 4       | func |     1 | Using where                  |
| NULL | UNION RESULT       | <union3,4,5> | ALL             | NULL          | NULL    | NULL    | NULL |  NULL |                              |
+----+--------------------+--------------+-----------------+---------------+---------+---------+------+-------+------------------------------+
7 rows in set (0.00 sec)

如果我使用 return 有 211 行(而不是 10547 行)的子查询,查询仍然会卡住。

mysql> show full processlist;
| 634878 | root | localhost | qid  | Query   |  104 | Sending data | select content from buttons where qid_id in (select distinct qid_id from groups_qids where group_id in (select 10 union select id from groups where parent_id=10)) |

更多好奇心... 对于这个查询: select 来自 qid_id 按钮的内容(select 与 groups_qids 不同的 qid_id,其中 group_id = 10); 它也需要永远。而且,有趣的是......那个子查询有 0 个结果,并且 MySQL 可以在 0.00 秒内计算出来。

content 是按钮上的 TEXT 类型,我猜这是这里问题的很大一部分......(虽然在最后一个查询中,你仍然认为它 return立即。)这是 table 定义中唯一让我印象深刻的部分,但这里是完整的部分:

mysql> desc buttons;
+--------------------+--------------+------+-----+---------+----------------+
| Field              | Type         | Null | Key | Default | Extra          |
+--------------------+--------------+------+-----+---------+----------------+
| id                 | int(11)      | NO   | PRI | NULL    | auto_increment |
| key                | varchar(50)  | NO   |     | NULL    |                |
| qid_id             | int(11)      | NO   | MUL | NULL    |                |
| button_type_id     | int(11)      | NO   |     | NULL    |                |
| title              | varchar(255) | NO   |     | NULL    |                |
| content            | text         | NO   |     | NULL    |                |
| sort               | int(11)      | NO   |     | NULL    |                |
| img                | varchar(50)  | NO   |     | NULL    |                |
| img_ext            | varchar(6)   | NO   |     | NULL    |                |
| parent             | tinyint(1)   | NO   |     | 0       |                |
| enabled            | tinyint(1)   | NO   |     | NULL    |                |
| share_gate         | tinyint(1)   | NO   |     | NULL    |                |
| deleted            | tinyint(1)   | NO   |     | NULL    |                |
| qr_id              | int(11)      | NO   |     | NULL    |                |
| function_type      | varchar(255) | NO   |     | NULL    |                |
| function_folder_id | int(11)      | NO   |     | NULL    |                |
+--------------------+--------------+------+-----+---------+----------------+

(1) 尝试将索引放在q_id中。 (2) 不使用IN,尝试加入子查询

SELECT content FROM buttons btns
JOIN 
    (SELECT distinct qid_id FROM groups_qids WHERE group_id IN
        (SELECT 5 
         UNION
         SELECT id FROM groups WHERE parent_id=5
         UNION
         SELECT id FROM groups WHERE parent_id IN 
           (SELECT id FROM groups WHERE parent_id=5))) tbl ON tbl.qid_id = btns.qid_id
WHERE btns.button_type_id=8;