有一个表用户使用主键作为user_id,并且索引列称为已验证。 另一个表user_profile将PK作为profile_id,将FK作为user_id,并且具有列名称
现在,我需要找到所有已验证的用户及其名称。所以我需要在user_id上加入这两个表 -
查询变为 -
select p.name from user_profile p inner join user u on p.user_id = u.user_id
where u.verified = 1;
配置文件表中有700000条记录,用户表中的记录数相同。上面的查询需要13秒才能运行。请告诉我,如何优化运行时间。
MySQL版本5.5,YII
CREATE TABLE IF NOT EXISTS `tbl_profile` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(10) unsigned NOT NULL,
`regyear` int(4) DEFAULT NULL,
`firstname` varchar(128) NOT NULL,
`gender` varchar(10) NOT NULL,
`occupation` int(5) NOT NULL,
`street` varchar(255) DEFAULT NULL,
`state` int(10) DEFAULT NULL,
`city` int(10) DEFAULT NULL,
`zip` int(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `state` (`state`),
KEY `firstname` (`firstname`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=626494 ;
-
tbl_user
CREATE TABLE IF NOT EXISTS `tbl_user` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`email` varchar(255) DEFAULT NULL,
`password` varchar(128) NOT NULL,
`createtime` int(10) NOT NULL DEFAULT '0',
`lastvisit` int(10) NOT NULL DEFAULT '0',
`status` int(1) NOT NULL DEFAULT '0',
`verified` int(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`),
KEY `status` (`status`),
KEY `verified` (`verified`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=626494 ;
EXPLAIN SELECT的输出 - 我写了与上面相同的查询,但用999代替1并使用列状态而不是验证,这相当于问题陈述。
EXPLAIN SELECT p.firstname
FROM tbl_profile p
INNER JOIN tbl_user u ON p.user_id = u.id
WHERE u.status =999
+----+-------------+-------+------+----------------+---------+---------+-------------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+----------------+---------+---------+-------------+--------+-------------+
| 1 | SIMPLE | u | ref | PRIMARY,status | status | 4 | const | 313333 | Using index |
| 1 | SIMPLE | p | ref | user_id | user_id | 4 | newone.u.id | 1 | |
+----+-------------+-------+------+----------------+---------+---------+-------------+--------+-------------+
答案 0 :(得分:2)
建议1
在(user_id, first_name)
上添加索引可以提高此特定查询的效率:
ALTER TABLE tbl_profile
ADD INDEX user_id_first_name_IX -- just a name for the index
(user_id, first_name) ;
但是如果你也有类似的查询,你选择其他列,你需要更多这样的索引。在表中添加5-10个索引并不算太糟糕(它只会减慢插入速度。)但是添加太多索引最终会有害。
建议2
如果每个用户最多有1个个人资料,则表id
中无需自动递增profiles
。我建议您删除该列并将user_id
作为主键。我也会把它作为外键:
ALTER TABLE tbl_profile
DROP PRIMARY KEY,
DROP COLUMN id,
ADD CONSTRAINT profile_PK
PRIMARY KEY (user_id),
ADD CONSTRAINT user_profile_FK
FOREIGN KEY (user_id)
REFERENCES tbl_user (id) ;
这远比建议1好,因为您基本上会使user_id
表的聚集索引。在此表上使用user_id
进行连接的任何查询都可以使用此(主要和群集)索引。
答案 1 :(得分:-1)
通过将条件移动到连接的ON
子句中,可以获得性能提升:
select p.name
from user_profile p
join user u on p.user_id = u.user_id and u.verified = 1;
这个可能表现更好的原因是在所有行加入后评估WHERE
子句 - 它是结果集上的过滤器。但是,当正在进行连接时,{em}评估ON
条件,因此数据库可能必须处理更少的行,因此内存/资源更少
除了这种改变,我看不到你能做的任何其他事情。