处理SELECT后加入

时间:2009-11-05 18:43:06

标签: sql optimization sqlite join

给出以下架构:

CREATE TABLE players (
  id BIGINT PRIMARY KEY,
  name TEXT UNIQUE
);

CREATE TABLE trials (
  timestamp TIMESTAMP PRIMARY KEY,
  player BIGINT,
  score NUMERIC
);

如何创建SELECT,首先从trials找到最佳分数,然后加入name的{​​{1}}字段?在使用此查询后,我已经能够获得分数:

users

我对返回前10个分数的查询如下:

SELECT * FROM trials GROUP BY player ORDER BY score ASC LIMIT 10;

但是当我在表中搜索数千个条目时,数据库性能开始爬行。我认为子查询正在扼杀我的表现。第一个查询(仅返回最高分数)仍然可以充分执行,因此我想知道是否有办法在选择最高分后强制CREATE VIEW top10place AS SELECT player.name AS name, trial.* FROM trials AS trial, players AS player WHERE trial.player = player.id AND trial.score = ( SELECT MAX(score) FROM trials AS tsub WHERE tsub.player = trial.player ) ORDER BY trial.score DESC, trial.timestamp ASC LIMIT 10; 操作。

编辑请注意,该查询将返回排名前10位的玩家,而不仅仅是排名前10位的玩家。如果同一个玩家有很多高分,他应该只出现在前10名中。

我正在使用SQLite,因此它没有SQL Server或MySQL的某些扩展功能。

4 个答案:

答案 0 :(得分:4)

没有运行sqlite,希望限制是正确的。

select players.name, trials.player, trials.timestamp, trials.score from
    (select player, score, timestamp from
    trials order by score desc, timestamp asc limit 10) trials, players
where players.id = trials.player

此致

答案 1 :(得分:1)

这是你做出比它需要更难的事情的一个例子。正确的代码是:

CREATE VIEW top10place AS
  SELECT player.name AS name, trial.*
    FROM trials AS trial, players AS player
    WHERE trial.player = player.id
    ORDER BY trial.score ASC, trial.timestamp ASC
    LIMIT 10;

基本上,让LIMIT语句完成工作:)

答案 2 :(得分:1)

如果优化器为每一行运行它,那么WHERE中的子查询可能会很昂贵。

(编辑)这是编写查询的另一种方法,现在使用独占连接:它表示该用户没有排得分更高的行:

SELECT 
     (select name from user where id = cur.userid) as UserName
,    cur.score as MaxScore
FROM trails cur
LEFT JOIN trials higher
    ON higher.userid = cur.userid
    AND higher.timestamp <> cur.timestamp
    AND higher.score > cur.score
WHERE higher.userid is null
ORDER BY cur.score DESC
LIMIT 10

这将返回10个得分最高的用户。如果您不管用户是否想要10个最高分,请查看Silas的答案。

答案 3 :(得分:1)

正如已经提到的,由于你在玩家和试验之间的识别关键是player.id和trials.player,你应该在trial.player上有一个索引。特别是如果你把这两张桌子关联起来的话。

您也可以尝试使查询更像。

SELECT p.name as name, t.* FROM players as p
INNER JOIN (SELECT * FROM trials WHERE trials.score = (SELECT MAX(score) FROM trials as tsub WHERE tsub.player = trials.player) LIMIT 10) as t ON t.player = p.id
ORDER BY t.score DESC, t.timestamp ASC

这甚至可以进行一些优化,但如果没有一些数据可以将查询抛出,我就不擅长了。