2009-02-22 2 views
8

나는 바보 같은 작은 게임을 작성했으며 일종의 리더 보드 웹 사이트를 갖고 싶습니다.리더 보드를위한 효율적인 SQL 쿼리/스키마

일반적으로 리더 보드는 10 명 또는 20 명의 최고 선수로 제한되지만, 기록 할 수 있다면 좋을 것 같습니다. 모든 플레이어에 대해 최고 점수는입니다. 그렇다면 항상 전 세계 순위를 표시 할 수 있습니다.

간단한 스키마는 다음과 같은 : - 자신의 최고 점수와 사용자 당 1 개 항목

create table leaderboard (
    userid varchar(128) not null, 
    score real not null, 
    when datetime not null 
); 
create index on leaderboard(userid); 

내가 필요한 최소한의 정보를 저장겠습니까.

제 질문은 리더 보드에서 누군가의 위치를 ​​효율적으로 결정하는 방법에 관한 것입니다.

select userid from leaderboard order by score desc 

그러나이 쿼리를 실행 한 후 선형 목록을 검색하는 것은 DB 성능 관점에서 나에게 조금 말도 안되는 것 같습니다 : 일반적인 생각은 내가 목록에서의 위치에 의해 반환 할 것입니다. 그렇다고해도 빠른 작업이 가능한 쿼리/스키마를 상상하기가 힘듭니다.

어떤 아이디어?

(한 업체가 나는 MS SQL 또는 MySQL의 하나를 사용하는 것이 행복이 쉽게 경우 나는 DB 스키마를 유지하고 (공급 업체에 연결되지 않음) 일반 쿼리하는 것을 선호합니다. 그러나 것이다.

답변

13

방법에 대해 :.

select count(*)+1 as rank from leaderboard 
where score > (select score from leaderboard where userid = ?) 

점수 열에도 색인이 필요합니다.

count()+1score > (...)을 사용하면 여러 플레이어의 점수가 같을 때에도 정확한 순위를 얻을 수 있습니다. 과 score >= (...)을 쓰는 것은 불가능합니다.

select userid , max(score) 
from leaderboard 
group by userid 
order by max(score) desc 

이 모든 사용자에 대해 1 개 항목과 함께 리더 보드를 반환 : 당신이 조회 할처럼

1

확실한에게 옵션은 "점수"에 대한 색인을 작성하는 것입니다. (누적 점수와 최고 점수라는 두 가지 값을 유지하려는 것 같습니다. 그렇지 않으면 오해하겠습니다.)

10을 예상하지 않으면 사용자의 수천, 심지어 테이블 스캔은 많은 레코드가있는 테이블에 큰 문제이어야한다

+0

설명을 위해 나는 최고 점수만을 저장하고 있습니다. –

+0

좋습니다, 그럼 최고의 점수에 대한 인덱스가 최선의 방법이 될 것입니다. 순위표에서 COUNT (1)를 선택하면 최고 스코어> = (SELECT score ... 등)가 효율적일 것입니다. 테이블 자체에 대한 참조없이 색인을 스캔하여 해결할 수 있기 때문입니다. – dkretz

1

보인다. 아래

편집 : 은 당신이 순위가 아닌 점수를 표시 할 주석을 참조하십시오. 이를 위해 나는 ANSI의 SQL의 대답을 잘 모르겠지만, 특정 데이터베이스 :

MySQL의에서 :

SELECT @rownum:[email protected]+1 rank 
, t.userid 
FROM (SELECT @rownum:=0) r, 
(select userid , score 
from leaderboard 
order by score desc 
) t; 

오라클에서 당신은 RANK 문을 사용할 수 있습니다.

+0

이것은 나에게 최고의 점수를 줄 것이다. 그러나 나는 그들의 "계급"을 "정상"에서 멀리 떨어진다. –

+0

훌륭합니다, 정말 고마워요. 일부 데이터베이스가이를 지원하는 것을 보니 다행입니다. –

1

이 (하루에 허용 한 번에 업데이트하는 경우, 예를 들어) 실시간 수없는 경우, 추가 "위치"필드를 추가하고 정기적으로 점수에 의해 주문 쿼리를 사용하여 업데이트합니다.

+0

확실히 좋은 옵션입니다. 나는 지금 오프라인 과정을 피하고 싶다. –

2

는 이후 SQL Server 2005에서는, 당신은 자신의 점수에 따라 각 사용자에 대한 순위를 반환 할 RANK() 기능을 사용할 수 있습니다

SELECT 
    userid, 
    RANK() OVER 
    (ORDER BY score) AS rank 
FROM leaderboard 

는 '게임 형'유형을 하나 이상 가지고 있다면, 당신은 리더 보드 테이블에이를 포함시키고 RANK 함수 내의 PARTITION BY 절을 사용하여 각 게임 유형의 순위를 결정할 수 있습니다.

1

SQL Server 2005에서 Rank()는 꽤 많은 일을합니다. 그러나 u에 수백만 개의 레코드가 있다면 기본 통계가 변경 될 때마다 실시간으로 순위를 매기면 실적 호그가됩니다.

내가 선택한 쿼리 맨 위에 색인 된보기를 만들려고했는데 ... (이 스레드에서 투표 응답)하지만 SQL 2005에서는 하위 뷰를 사용할 수 없기 때문에 SQL을 만들지 않습니다. 인덱스 된 뷰에서 자체 참조 .

해결 방법은 Row() 함수를 사용하여 야간 순위 테이블을 업데이트하는 것입니다. 이 업데이트를 수행하는 동안 차단을 피하기 위해 우리는 업데이트되는 순위 테이블과 응용 프로그램에서 사용되는 순위 테이블을 2 부 유지합니다. 주어진 시간에 활성 순위 테이블을 가리키는 RankingView가 있습니다.

정말 큰 테이블의 실시간 순위 업데이트를위한 해결책이 있는지 알고 싶습니다.

0
나는 다음과 같은 상황의

생각해 선택 "리더
점수> (리더 보드에서 점수를 선택 사용자 ID =?)에서 순위로 SELECT COUNT (*) + 1"에 대해 생각했다

: 플레이어 1, SQL은 플레이어 3의 순위에 연결되어 플레이어 1과 플레이어 2 때문에 정답이 있어야한다 (3), 것이라고 사용 50

점수, 100 선수 3 점수 100 플레이어 2 점수 첫 번째 위치. 카운트()이 경우에 집계 함수 점수 열이이 개 기록을 고려> (50)

내가 올바른 옵션은 단일 순위로 처리됩니다 점수를 너무 반복 값으로 그룹을 만들 생각이 사건을 처리하려면 위치 :

select score, count(*)+1 as rank from leaderboard 
group by score having (score) > (select score from leaderboard where userid = ?)