从table1连接table2中选择列,需要很长时间

时间:2017-07-26 09:08:24

标签: mysql join indexing

我有2张桌子。从这两个表我想尝试使用带连接的选择查询将记录插入第三个表。但是我发现选择查询时加入不使用索引并花费大量时间,因此插入速度很慢 我尝试按照几篇文章的建议创建多个索引,但没有用 MySQL with JOIN not using index
MySQL query with JOIN not using INDEX

以下是我的表结构:

CREATE TABLE master_table (
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
field1 VARCHAR(50) DEFAULT NULL,
field2 VARCHAR(50) DEFAULT NULL,
field3 VARCHAR(50) DEFAULT NULL,
field4 VARCHAR(50) DEFAULT NULL,
PRIMARY KEY (id),
KEY mt_field1_index (field1)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

CREATE TABLE child_table (
c_id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
m_id BIGINT(20) UNSIGNED NOT NULL ,
group_id BIGINT(20) UNSIGNED NOT NULL ,
status ENUM('Status1','Status2','Status3') NOT NULL,
job_id VARCHAR(50) DEFAULT NULL,
PRIMARY KEY (c_id),
UNIQUE KEY ct_mid_gid (m_id,group_id),
KEY Index_ct_status (status),
KEY index_ct_jobid (job_id),
KEY index_ct_mid (m_id),
KEY index_ct_cid_sts_tsk (group_id,status,job_id)
) ENGINE=INNODB DEFAULT CHARSET=utf8;  

查询:

SELECT m.id
     , NULLIF(TRIM(m.field1),'')
  FROM master_table m 
  JOIN child_table c 
    ON m.id = c.m_id 
 WHERE c.group_id = 2 
   AND c.status = 'Status3' 
   AND c.job_id = 0 
 ORDER 
    BY m.id  
 LIMIT 0, 1000;

解释:

+-------+-------------+-------+------------+----------+------------------------------------------------------------------------------+-----------------+---------+--------------+-------+----------+------------------------------------------------+
|    id | select_type | table | partitions |   type   |                                possible_keys                                 |       key       | key_len |     ref      | rows  | filtered |                     Extra                      |
+-------+-------------+-------+------------+----------+------------------------------------------------------------------------------+-----------------+---------+--------------+-------+----------+------------------------------------------------+
|     1 | SIMPLE      |    c  |    (NULL)  |   ref    |  ct_mid_gid,Index_ct_status,index_ct_jobid,index_ct_mid,index_ct_cid_sts_tsk | Index_ct_status |       1 | const        | 65689 |     0.00 | Using where; Using temporary; Using filesort   |
|     1 | SIMPLE      |    m  |    (NULL)  |   eq_ref | PRIMARY                                                                      | PRIMARY         |       8 | r_n_d.c.m_id |     1 |   100.00 | (NULL)                                         |
+-------+-------------+-------+------------+----------+------------------------------------------------------------------------------+-----------------+---------+--------------+-------+----------+------------------------------------------------+

2 个答案:

答案 0 :(得分:1)

 WHERE c.group_id = 2 
   AND c.status = 'Status3' 
   AND c.job_id = 0 
 ORDER BY c.m_id     -- Note the change

需求

 INDEX(group_id, status, job_id,   -- in any order
       m_id)                       -- last

你拥有的(单独的索引)相同。

要获得LIMIT,索引必须完全超过WHEREORDER BY。这样可以防止计算所有行(在LIMIT之前)并进行排序,然后再执行LIMIT

所以,你获得了4次加速:

  • 有效获取所需行的索引(来自c
  • 不需要排序传递(因为ORDER BY按顺序传递它们)
  • 索引是"覆盖" (因此,不会在索引BTree和c的数据BTree之间来回反弹)
  • 停在1000处。

当你在这里时,考虑摆脱AUTO_INCREMENT。抛出c_id并更改

PRIMARY KEY (c_id),
UNIQUE KEY ct_mid_gid (m_id, group_id)

- >

PRIMARY KEY(m_id, group_id)

巧合的是,如果你这样做了,你的KEY index_ct_cid_sts_tsk (group_id,status,job_id)会偶然发现完美的索引。这是因为PK隐式添加到任何辅助索引上,但您需要m_id c_id。无论如何,我更喜欢明确。

进行更改时,丢弃任何冗余索引。例如,KEY index_ct_mid (m_id)是无用的,因为它是另一个索引的开头。

答案 1 :(得分:0)

您是否在where子句中使用的列上创建了索引? 通过在列上添加索引来检查查询。

但请记住,如果添加索引然后在表上插入,更新和删除操作可能会变慢。