【问题标题】:MySQL query takes over 15 minutes, doesn't seem like its THAT much dataMySQL 查询需要超过 15 分钟,似乎没有那么多数据
【发布时间】:2016-05-18 22:23:27
【问题描述】:

所以,这是我的查询:

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;

基本上,有一个名为groups的表,我想找到2个级别内指向group_id=5作为其父级的所有组。这些组通过groups_qids 与一个qids 表相关联,所以我想找到与我刚刚找到的所有这些组相关联的所有qid。

然后,我们有指向 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 秒内运行,返回 10547 行。

按钮表中有 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)

如果我使用返回 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)) |

更多好奇... 对于此查询: 从 qid_id 所在的按钮中选择内容(从 group_qids 中选择不同的 qid_id,其中 group_id = 10); 它也需要永远。而且,有趣的是……那个子查询有 0 个结果,MySQL 可以在 0.00 秒内计算出来。

content 是按钮上的 TEXT 类型,我猜这是问题的很大一部分...(尽管在最后一个查询中,您仍然认为它会立即返回。)这是唯一的表定义的一部分对我来说很突出,但这是完整的:

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    |                |
+--------------------+--------------+------+-----+---------+----------------+

【问题讨论】:

  • 问题是如果像你这样使用嵌套子查询,你无法预测操作的实际计算成本。我的猜测是,您在“SELECT id FROM groups WHERE parent_id IN (SELECT id FROM groups WHERE parent_id=5))”中的嵌套子查询正在减慢一切。另外,您正在运行 SELECT id FROM groups WHERE parent_id=5 两次,这不是最佳的。我建议您分解查询,单独运行嵌套查询并将它们存储在变量中,将它们联合起来。除此之外,您可以看看 EXISTS 运算符,它运行得更快。
  • 请发布您所有相关的表结构,我的意思是创建表代码并显示一些示例输入和预期输出。 @汤姆
  • 您应该“加入”表而不是“嵌套”查询。
  • 让我把这个简单,我可以做这个查询: 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)) 这给了我大约 10k 的结果,只需要几分之一秒。该查询是一个 ID 列表。然后从那个中间查询中,我想从@thatintermediatequeryresult 中的qid_id 按钮中选择内容;我可以这样做吗?我不认为中间查询有任何性能问题...外部查询搞砸了...

标签: mysql database performance database-design relational-database


【解决方案1】:

(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;

【讨论】:

  • 谢谢...这个成功了。我试图像其他用户提到的那样降低 EXISTS 子查询样式,但很难使其工作。由于对我来说问题出在最外面的查询中,因此将那个从 IN 更改为 JOIN 对我来说很有效。
  • IN (SELECT ... ) 构造的效率低于其他选项。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-17
  • 2010-12-11
  • 2019-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多