双连接查询需要 540 秒才能运行 - 我怎样才能加快速度?

Posted

技术标签:

【中文标题】双连接查询需要 540 秒才能运行 - 我怎样才能加快速度?【英文标题】:Two-join query is taking 540 seconds to run - how can I speed this up? 【发布时间】:2013-03-05 05:02:05 【问题描述】:

一个特定的查询需要非常很长时间才能运行,大约 540 秒(是的,9 分钟!)。这会导致负载峰值。

有没有办法可以重写查询 - 或添加索引 - 以加快速度? 发生了。

查询

select DISTINCT tab3.id 
from `tab1`  
left join `tab2` on tab2.element_id = tab1.resource_id 
    and tab1.resource_type = 2 
    and tab2.element_type_id = 1 
left join `tab3` on tab2.tab3nt_id = tab3.id  
where tab1.group_tab1_id = 1 
    and tab1.domain_id = 2 
    and tab3.domain_id = 2 
    and tab3.tab3nt_start_date >= '2012-12-01'  
    and tab3.tab3nt_start_date <= '2013-03-01'

解释计划

+----+-------------+-------+--------+-------------------------------------------------------------------------------------+----------------------------+---------+-------------------------------+------+-------------------------------------------+
| id | select_type | table | type   | possible_keys                                                                       | key                        | key_len | ref                           | rows | Extra                                     |
+----+-------------+-------+--------+-------------------------------------------------------------------------------------+----------------------------+---------+-------------------------------+------+-------------------------------------------+
|  1 | SIMPLE      | tab1   | ref    | group_tab1_id_resource_id,domain_id,domain_id_resource_type,tgtr_resource_domain_key | domain_id                  | 13      | const,const,const           |  962 | Using where; Using index; Using temporary |
|  1 | SIMPLE      | tab2   | ref    | FK_tab3nt,element_type_id_element_id                                                 | element_type_id_element_id | 8       | const,svr.tab1.resource_id  |   14 | Using where                               |
|  1 | SIMPLE      | tab3   | eq_ref | PRIMARY,domain_id_tab3nt_type_cd                                                     | PRIMARY                    | 4       | svr.tab2.tab3nt_id          |    1 | Using where                               |
+----+-------------+-------+--------+-------------------------------------------------------------------------------------+----------------------------+---------+-------------------------------+------+--------

表结构

mysql> show create table tab1\G
*************************** 1. row ***************************
       Table: tab1
Create Table: CREATE TABLE `tab1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `domain_id` int(11) NOT NULL,
  `group_tab1_id` int(11) NOT NULL,
  `resource_id` int(11) NOT NULL,
  `resource_type` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `group_tab1_id_resource_id` (`group_tab1_id`,`resource_id`),
  KEY `domain_id` (`domain_id`,`group_tab1_id`,`resource_type`,`resource_id`),
  KEY `domain_id_resource_type` (`domain_id`,`resource_type`),
  KEY `tgtr_resource_domain_key` (`resource_id`,`domain_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2039461 DEFAULT CHARSET=latin1
1 row in set (0.01 sec)

mysql> show create table tab2\G
*************************** 1. row ***************************
       Table: tab2
Create Table: CREATE TABLE `tab2` (
  `id` int(255) NOT NULL AUTO_INCREMENT,
  `element_type_id` int(11) NOT NULL,
  `tab3nt_id` int(11) NOT NULL,
  `element_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `FK_tab3nt` (`tab3nt_id`),
  KEY `element_type_id_element_id` (`element_type_id`,`element_id`)
) ENGINE=InnoDB AUTO_INCREMENT=53195543 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

mysql> show create table tab3\G
*************************** 1. row ***************************
       Table: tab3
Create Table: CREATE TABLE `tab3` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `create_user_id` int(11) DEFAULT NULL,
  `tab3nt_type_cd` int(11) NOT NULL,
  `tab3nt_start_date` datetime NOT NULL,
  `tab3nt_end_date` datetime NOT NULL,
  `domain_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `tab3nt_user_FK` (`create_user_id`),
  KEY `domain_id_tab3nt_type_cd` (`domain_id`,`tab3nt_type_cd`)
) ENGINE=InnoDB AUTO_INCREMENT=9393276 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

【问题讨论】:

我不认为您的 540 毫秒仅用于运行此查询...您使用什么语言运行此查询 @BhushanFirake 如果我没看错的话,不是 540 毫秒,而是 540 秒 @pvr 请澄清——是 540 毫秒 还是 540 ( 9 分钟)?如果是 540 毫秒,您可能不会得到太大的改进,尤其是在数据库是远程的情况下。如果是 9 分钟,则说明其他问题,因为您没有选择很多行。 @DreamEater 哦,天哪……我的错……从不关心毫秒或秒,只是假设它是ms。从来没有花太多时间进行任何查询...操作一定是在其他地方出错了... 它运行了 540 秒。 【参考方案1】:

尝试在 tab2.element_id 上放置一个简单(非复合)索引。

【讨论】:

【参考方案2】:

我没有测试过这个查询,因为目前我没有访问 MySql 数据库的权限,但可以尝试这样的事情:

SELECT DISTINCT tab3.id 
FROM 'tab1'
INNER JOIN 'tab2' 
      ON tab2.element_id = tab1.resource_id 
INNER JOIN 'tab3' 
      ON tab2.tab3nt_id = tab3.id
WHERE tab1.group_tab1_id = 1
    AND tab1.domain_id = 2
    AND tab3.domain_id = 2
    AND tab1.resource_type = 2
    AND tab2.element_type_id = 1
    AND tab3.tab3nt_start_date between '2012-12-01' and '2013-03-01'

【讨论】:

在表名中使用`(反引号)而不是'。另外,需要注意的是:我认为在这个查询中 INNER JOIN 而不是 LEFT JOIN 是一个很好的优化,但这并不总是可行的方法,因为两者给出了不同的结果集。最后:首先测试,然后接受答案;) 但查询需要同样长的时间。 我不知道它是否有帮助,但我更新了答案中的查询【参考方案3】:

如果您希望表 tab3 上有不同的 id,我会重新排序表并使用内连接而不是左连接。

SELECT DISTINCT tab3.id 
FROM 'tab3' 
INNER JOIN 'tab2'
  ON tab2.tab3nt_id = tab3.id 
INNER JOIN 'tab1'
  ON tab2.element_id = tab1.resource_id
WHERE tab1.group_tab1_id = 1 
AND tab1.domain_id = 2
AND tab3.domain_id = 2
AND tab1.resource_type = 2
AND tab2.element_type_id = 1
and tab3.tab3nt_start_date >= '2012-12-01'  
and tab3.tab3nt_start_date <= '2013-03-01'

【讨论】:

以上是关于双连接查询需要 540 秒才能运行 - 我怎样才能加快速度?的主要内容,如果未能解决你的问题,请参考以下文章

SQL 查询优化需要 20 - 30 秒才能运行

我怎样才能让我的 caroutine 每 x 秒运行一次

我怎样才能提高性能

怎样才能测试WEB系统支持多少用户

查询需要很长时间才能执行大约 120 秒

长选需要 55 秒才能显示结果,更好的咨询方式?