适用于大型表的MySQL查询优化

时间:2014-09-22 18:01:34

标签: mysql sql optimization

我的查询需要50秒

SELECT `security_tasks`.`itemid` AS `itemid`
FROM `security_tasks`
INNER JOIN `relations` ON (`relations`.`user_id` = `security_tasks`.`user_id` AND    `relations`.`relation_type_id` = `security_tasks`.`relation_type_id` AND `relations`.`relation_with` = 3001 )  

security_tasks = 841321 ||中的记录关系记录= 234254

CREATE TABLE `security_tasks` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL,
  `itemid` int(11) DEFAULT NULL,
  `relation_type_id` int(11) DEFAULT NULL,
  `Task_id` int(2) DEFAULT '0',
  `job_id` int(2) DEFAULT '0',
  `task_type_id` int(2) DEFAULT '0',
  `name` int(2) DEFAULT '0'
  PRIMARY KEY (`id`),
  KEY `itemid` (`itemid`),
  KEY `relation_type_id` (`relation_type_id`),
  KEY `user_id` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1822995 DEFAULT CHARSET=utf8;

CREATE TABLE `relations` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL,
  `relation_with` int(11) DEFAULT NULL,
  `relation_type_id` int(11) DEFAULT NULL,
  `manager_level` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `user_id` (`user_id`),
  KEY `relation_with` (`relation_with`),
  KEY `relation_type_id` (`relation_type_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1082882 DEFAULT CHARSET=utf8;

我该怎么做才能让它快速,比如快1或2秒

EXPLAIN:

id select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  relations   ref user_id,relation_with,relation_type_id  relation_with   5   const   169 Using where
1   SIMPLE  security_tasks  ref relation_type_id,user_id    user_id 5   transparent.relations.user_id   569 Using where

更新:

添加复合键可将时间缩短至20秒

ALTER TABLE security_tasks ADD INDEX(user_id,relation_type_id); ALTER TABLE关系ADD INDEX(user_id,relation_type_id); ALTER TABLE关系ADD INDEX(relation_with);

问题是当关系表包含所选用户的大数据时(关系. relation_with` = 3001)

任何想法?

1 个答案:

答案 0 :(得分:0)

稍微调整复合指数,不要只做两个,而是全部三个部分

ALTER TABLE关系ADD INDEX(user_id,relation_type_id,relation_with)

索引不仅必须在连接列上,而且应该基于连接列PLUS任何其他有意义的查询标准(在合理范围内,需要时间来学习更高的效率)。因此,在建议的情况下,您知道用户和类型的连接,但也特定于与...的关系,因此将其添加到同一索引中。

此外,您的安全任务表,您可以将itemID添加到索引以使其成为覆盖索引(即:覆盖连接条件和您要检索的数据元素)。这也是一种技术,不应该包含查询中的所有其他元素,但由于这是单个列可能对您的方案有意义。因此,查看“覆盖索引”,但实质上,覆盖索引限定了连接,但由于它也具有此“itemid”,因此引擎不必返回整个安全任务表的原始数据页面得到那一列。它是索引的一部分,所以它抓住任何合格的加入并且为了骑行而来,你就完成了。

ALTER TABLE security_tasks ADD INDEX(user_id,relation_type_id,itemid);

为了便于阅读,特别是对于长表名,最好使用别名

SELECT 
      st.itemid
   FROM 
      security_tasks st
         INNER JOIN relations r
            ON st.user_id = r.user_id 
            AND st.relation_type_id = r.relation_type_id
            AND r.relation_with = 3001