我如何加快这个mysql查询?
SET @rank = 0;
UPDATE dbTable
SET rank_fd = @rank := @rank + 1
ORDER BY fd2 DESC, fd3 DESC;
此查询更新~300,000个表行。它只需要太长时间....简单的控制面板(涡轮增压面板?)说mysqld只使用8-9%的CPU。我知道这总是如此,但这个查询在我的Core i7机器上花费的时间差不多。我认为我的P4专用服务器需要大约5-10分钟...这不会是一个问题,除非我不得不为不同的值做多次。它还使得其他mysql操作极其缓慢(几乎挂起),这极大地影响了网站性能。
软件:
硬件:
更多信息(2011年3月6日美国中部时间下午10点06分):
//Core i7 920 @ 2.6GHz, 6GB Ram
UPDATE dbTable SET rank_fd =999999999;
#275037 row(s) affected. ( Query took 7.0708 sec )
SET @rank =0;
#Your SQL query has been executed successfully ( Query took 0.0003 sec )
UPDATE dbTable SET rank_fd = @rank := @rank +1 ORDER BY fd2 DESC, fd3 DESC ;
#275037 row(s) affected. ( Query took 9.9931 sec )
//P4 3.0GHz, 2GB Ram
UPDATE dbTable SET rank_fd =999999999;
#Affected rows: 291468 (Query took 8.2165 sec)
SET @rank =0;
#Your SQL query has been executed successfully (Query took 0.0002 sec)
UPDATE dbTable SET rank_fd = @rank := @rank +1 ORDER BY fd2 DESC, fd3 DESC ;
#Affected rows: 291469 (Query took 305.2104 sec)
更多信息(2011年3月7日下午6:37 CST):
我有一些新信息。如果我在P4上做一个select语句:
SET @rank =0;
SELECT @rank := @rank +1 AS rank_fd FROM dbTable ORDER BY fd2 DESC, fd3 DESC LIMIT 0, 300000;
#Showing rows 0 - 29 (292,437 total, Query took 3.0448 sec)
计算一切只需3秒钟。无计量批量更新语句仅需8秒。正在进行的所有额外工作是什么导致它在我的原始声明中超过300秒。有没有办法在不涉及PHP的select calc语句之后捕获更新。我只是这样说,因为如果我在PHP中循环它,它将比原始语句花费更长的时间。
感谢迄今为止的所有帮助!!!
答案 0 :(得分:3)
你正在修改表格中的每一行,当然它会很慢。根据{{1}}的使用方式,您可以在rank_fd
和fd2
上放置索引并在运行时计算排名。
答案 1 :(得分:0)
您可以使用存储过程和临时表来加快排名过程。
以下示例使用一个玩家得分表,其中包含150万行,500个玩家得分超过3轮(500K * 3),并更新第1轮(500K行)的排名。 5秒。
希望这会有所帮助:)
示例表和存储过程
drop table if exists player_scores;
create table player_scores
(
round_id smallint unsigned not null,
player_id int unsigned not null,
score_1 int unsigned not null default 0,
score_2 int unsigned not null default 0,
rank int unsigned not null default 0,
primary key (round_id, player_id)
)
engine=myisam;
drop procedure if exists update_player_score_ranking;
delimiter #
create procedure update_player_score_ranking
(
p_round_id smallint unsigned
)
begin
create table tmp_player_scores engine=memory select
round_id, player_id, score_1, score_2, @rank:= @rank + 1 as rank
from
player_scores
inner join (select @rank:=0) r
where
round_id = p_round_id
order by
score_1 desc, score_2 desc;
delete from player_scores where round_id = p_round_id;
insert into player_scores select * from tmp_player_scores;
drop table if exists tmp_player_scores;
end #
delimiter ;
测试结果:
select count(*) from player_scores;
+----------+
| count(*) |
+----------+
| 1500000 |
+----------+
1 row in set (0.00 sec)
select count(*) from player_scores where round_id = 1;
+----------+
| count(*) |
+----------+
| 500000 |
+----------+
1 row in set (0.07 sec)
select * from player_scores where round_id = 1 order by score_1 desc, score_2 desc limit 5;
+----------+-----------+---------+---------+------+
| round_id | player_id | score_1 | score_2 | rank |
+----------+-----------+---------+---------+------+
| 1 | 456937 | 65534 | 49579 | 0 |
| 1 | 72439 | 65534 | 44537 | 0 |
| 1 | 16427 | 65534 | 43045 | 0 |
| 1 | 259871 | 65534 | 32095 | 0 |
| 1 | 324702 | 65534 | 15227 | 0 |
+----------+-----------+---------+---------+------+
5 rows in set (0.71 sec)
call update_player_score_ranking(1);
Query OK, 0 rows affected (5.57 sec)
select * from player_scores where round_id = 1 order by rank limit 5;
+----------+-----------+---------+---------+------+
| round_id | player_id | score_1 | score_2 | rank |
+----------+-----------+---------+---------+------+
| 1 | 456937 | 65534 | 49579 | 1 |
| 1 | 72439 | 65534 | 44537 | 2 |
| 1 | 16427 | 65534 | 43045 | 3 |
| 1 | 259871 | 65534 | 32095 | 4 |
| 1 | 324702 | 65534 | 15227 | 5 |
+----------+-----------+---------+---------+------+
5 rows in set (1.29 sec)