Sql 处理后加入选择

Sql 处理后加入选择,sql,optimization,sqlite,join,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,首先从试用中找到最好的分数,然后从用户那里加入name字段?使用此查询后,我已能够获得我的分数: SELECT * FROM

给定以下模式:

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

CREATE TABLE trials (
  timestamp TIMESTAMP PRIMARY KEY,
  player BIGINT,
  score NUMERIC
);
我如何创建一个SELECT,首先从试用中找到最好的分数,然后从用户那里加入name字段?使用此查询后,我已能够获得我的分数:

SELECT * FROM trials GROUP BY player ORDER BY score ASC LIMIT 10;
我返回前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;
但是,当我在表中点击数千个条目时,DB性能开始爬升。我认为子查询正在扼杀我的性能。第一个只返回最高分的查询仍能充分执行,因此我想知道是否有办法在选择最高分后强制执行联接操作

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


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

这是一个使事情变得比需要的更困难的例子。正确的代码是:

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语句来完成这项工作:

如果优化器为每一行运行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的答案。

正如前面提到的,因为您在玩家和试用之间的识别键是player.id和trials.player,因此您应该在trials.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

这甚至可以再优化一点,但如果没有一些数据来抛出查询,我就不擅长这样做。

没有运行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

关于

是否应该按试用顺序排列。分数描述?这种方法的问题是,如果同一名球员必须获得前10名的分数,他们都会出现。我在寻找排名靠前的球员,所以这个列表中只有唯一的球员。@Andomar是的,那是我的错。。。我最初的问题有一个拼写错误。这种方法在我的数据库上也非常慢,有10000名玩家和100000次试用。它需要几分钟才能完成。你能提供另一种可能性吗?@jheddings:编辑后可以用另一种方式来写这个问题。。。使用这种方法在<2秒内执行的查询,如果使用索引,则执行时间<500毫秒。谢谢