优化MySQL查询的运行时间
有一个表users,主键为user_id,索引列为verified。 另一个表user_profile将PK作为profile_id,将FK作为user_id,并具有一个列名 现在,我需要找到所有已验证的用户及其姓名。所以我需要在user_id上连接这两个表- 查询变为-优化MySQL查询的运行时间,mysql,yii,Mysql,Yii,有一个表users,主键为user_id,索引列为verified。 另一个表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
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
编辑
-- --表
tbl\u用户的表结构
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 | |
+----+-------------+-------+------+----------------+---------+---------+-------------+--------+-------------+
建议1
在(用户id,名字)
上添加索引将提高此特定查询的效率:
ALTER TABLE tbl_profile
ADD INDEX user_id_first_name_IX -- just a name for the index
(user_id, first_name) ;
但是,如果您也有类似的查询,在其中选择其他列,您将需要更多这样的索引。在表中添加5-10个索引并不太糟糕(这只会使插入速度减慢一点),但添加太多的索引最终将是有害的
建议2
如果每个用户最多有一个配置文件,则不需要在表配置文件中有一个自动递增的id
。我建议您删除该列,并将user\u 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\u id
作为表的聚集索引。对于此表上的联接,任何使用user\u id
的查询都可以使用此(主索引和聚集索引)。您可以通过将条件移动到联接的on
子句中来获得性能改进:
select p.name
from user_profile p
join user u on p.user_id = u.user_id and u.verified = 1;
之所以它的性能更好,是因为WHERE
子句是在所有行都被联接之后计算的,它是结果集上的一个过滤器。但是,
上的条件是在进行连接时计算的,因此数据库可能需要处理更少的行,从而需要更少的内存/资源
除此之外,我看不到您还能做什么。表上有哪些索引?添加两个表的CREATE TABLE
语句和EXPLAIN SELECT…
的输出一个用户可以有多个配置文件吗?不,一个用户只有一个配置文件,我想你会建议加入它们并创建一个表吗?实际上,用户表只用于登录,而另一个表有与配置文件相关的数据。不,我已经添加了我的建议作为答案。不知道Yii是否会对这一变化有任何问题。一些ORM/框架在没有自动递增PKs的表上存在问题。我不知道为什么会出现向下投票,我必须尝试每个建议,看看哪个运行得最快。尝试它们是非常明智的。通常,这是处理查询的最快和最好的方法-进行一些更改并比较时间。如果您正在测试所有答案,那么在所有答案中添加一条注释,说明它的性能,对每个人都有帮助
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) ;
select p.name
from user_profile p
join user u on p.user_id = u.user_id and u.verified = 1;