mysql 7 +加入一个表,如何加快速度?

Posted

技术标签:

【中文标题】mysql 7 +加入一个表,如何加快速度?【英文标题】:mysql 7 + joins on a table, how to speed up? 【发布时间】:2017-11-19 05:11:33 【问题描述】:

我有 7 张桌子。表 1 是“父表”和has_many 与表 2-7 的关系。

我想做一个查询来获取表 1 的行,其中包含表 2-7 中的 id 列表。我已经尝试了以下查询,但是对于大型数据库,我的查询需要 15 秒。我想知道如何使这个查询更快?

编辑几点说明: -> 删除 Distinct 只节省 4 秒,我仍然得到 10-11 秒的查询

-> 从查询中删除 1 个连接表(不管哪个)将时间从 15 秒减少到 2-3 秒。删除 2 个连接表(同样无关紧要)将查询减少到 1/2 秒。

SELECT  
  table1.table1_id as table1Id, 
  GROUP_CONCAT(DISTINCT table2.table2_id) AS table2Ids,
  GROUP_CONCAT(DISTINCT table3.table3_id) AS table3Ids,
  GROUP_CONCAT(DISTINCT table4.table4_id) AS table4Ids,
  GROUP_CONCAT(DISTINCT table5.table5_id) AS table5Ids,
  GROUP_CONCAT(DISTINCT table6.table6_id) AS table6Ids,
  GROUP_CONCAT(DISTINCT table7.table7_id) AS table7Ids
  FROM table1
  LEFT JOIN table2 ON table1.table1_id = table2.table1_id
  LEFT JOIN table3 ON table1.table1_id = table3.table1_id
  LEFT JOIN table4 ON table1.table1_id = table4.table1_id
  LEFT JOIN table5 ON table1.table1_id = table5.table1_id
  LEFT JOIN table6 ON table1.table1_id = table6.table1_id
  LEFT JOIN table7 ON table1.table1_id = table7.table1_id
  WHERE table1.archived = false
  GROUP BY table1.table1_id LIMIT 1000

我的解释查询:

+----+-------------+------------------+------------+-------+----------------------------------------------------------------------------------------------------+---------------------------+---------+--------------------------+------+----------+-------------+
| id | select_type | table            | partitions | type  | possible_keys                                                                                      | key                       | key_len | ref                      | rows | filtered | Extra       |
+----+-------------+------------------+------------+-------+----------------------------------------------------------------------------------------------------+---------------------------+---------+--------------------------+------+----------+-------------+
|  1 | SIMPLE      | table1           | NULL       | index | PRIMARY,unique_name_in_table8, table8_idx,table9_idx,table10_idx                                   | PRIMARY                   | 4       | NULL                     |    1 |    10.00 | Using where |
|  1 | SIMPLE      | table2           | NULL       | ref   | PRIMARY                                                                                            | PRIMARY                   | 4       | db.table1.table1_id      |   20 |   100.00 | Using index |
|  1 | SIMPLE      | table3           | NULL       | ref   | table3_to_table1_id_idx                                                                            | table3_to_table1_id_idx   | 4       | db.table1.table1_id      |  824 |   100.00 | Using index |
|  1 | SIMPLE      | table4           | NULL       | ref   | table4_word_unique,table4_to_table1_id_idx                                                         | table4_to_table1_id_idx   | 4       | db.table1.table1_id      |    4 |   100.00 | Using index |
|  1 | SIMPLE      | table5           | NULL       | ref   | table5_to_table1_id_idx                                                                            | table5_to_table1_id_idx   | 4       | db.table1.table1_id      |   26 |   100.00 | Using index |
|  1 | SIMPLE      | table6           | NULL       | ref   | table6_to_table1_id_idx                                                                            | table6_to_table1_id_idx   | 4       | db.table1.table1_id      |    3 |   100.00 | Using index |
|  1 | SIMPLE      | table7           | NULL       | ref   | table7_to_table1_id_idx                                                                            | table7_to_table1_id_idx   | 4       | db.table1.table1_id      |  483 |   100.00 | Using index |
+----+-------------+------------------+------------+-------+----------------------------------------------------------------------------------------------------+---------------------------+---------+--------------------------+------+----------+-------------+

【问题讨论】:

是否可以消除distinct ? AFAIK,它会给后端带来负担。 @PrabhatG 我添加了一条评论。消除 distinct 只节省 4 秒,我宁愿没有重复。有没有更有效的方法来运行这个查询? 你能加入这个Stack Overflow Chat (chat.***.com/rooms/146828/…) 也许将 table#_ID 添加到索引中,这样 table1_ID、table#_ID 就是一个复合索引。 【参考方案1】:

我试图重写查询。试着让我知道。我没有测试过。

SELECT  
  t1.table1Id, 
  GROUP_CONCAT(DISTINCT table2.table2_id) AS table2Ids,
  GROUP_CONCAT(DISTINCT table3.table3_id) AS table3Ids,
  GROUP_CONCAT(DISTINCT table4.table4_id) AS table4Ids,
  GROUP_CONCAT(DISTINCT table5.table5_id) AS table5Ids,
  GROUP_CONCAT(DISTINCT table6.table6_id) AS table6Ids,
  GROUP_CONCAT(DISTINCT table7.table7_id) AS table7Ids
FROM (
    SELECT table1_id as table1Id
    FROM table1
    WHERE table1.archived = false
    GROUP BY table1.table1_id LIMIT 1000
      ) AS t1
  INNER JOIN table2 ON t1.table1Id = table2.table1_id
  INNER JOIN table3 ON t1.table1Id = table3.table1_id
  INNER JOIN table4 ON t1.table1Id = table4.table1_id
  INNER JOIN table5 ON t1.table1Id = table5.table1_id
  INNER JOIN table6 ON t1.table1Id = table6.table1_id
  INNER JOIN table7 ON t1.table1Id = table7.table1_id

【讨论】:

【参考方案2】:

解释说table2table1Id 上没有索引。

试试:

create index table2_to_table1_id_idx on table2(table1Id);

这可能会充分提高性能,但要最大限度地提高此特定查询的性能,请创建覆盖索引:

 create index table2_table1_id_idx on table2(table1Id, table2Id);
 create index table3_table1_id_idx on table3(table1Id, table3Id);
 create index table4_table1_id_idx on table4(table1Id, table4Id);
 create index table5_table1_id_idx on table5(table1Id, table5Id);
 create index table6_table1_id_idx on table6(table1Id, table6Id);
 create index table7_table1_id_idx on table7(table1Id, table7Id);

拥有这些索引意味着您可以完全避免访问基表。

【讨论】:

学习者的好奇心。你能解释一下你的答案吗?您如何通过explain 确定索引是否不存在。覆盖索引如何避免完全命中基表?

以上是关于mysql 7 +加入一个表,如何加快速度?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 MySQL 5 .7 中实现 CTE 功能?

是否可以加快 MySQL 的“更新参考表”线程状态?

如何安装mysql5.7.17

centos7-mysql-索引优化

mysql5.7 pxc

如何安装mysql 5.7.9?