2012-05-14 2 views
2

내 케이스 세부 사항에 대해 편집되었습니다.Seek가 내 mysql 쿼리의 속도를 높이는 데 도움이됩니다.

CREATE TABLE IF NOT EXISTS `tbl_user` (
    `id` int(50) NOT NULL auto_increment, 
    `fbuid` bigint(20) unsigned NOT NULL, 
    `fullname` varchar(255) NOT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `fbuid` (`fbuid`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=7 ; 

INSERT INTO `tbl_user` (`id`, `fbuid`, `fullname`) VALUES 
(1, 1002, 'User B'), 
(2, 1001, 'User A'), 
(3, 1003, 'User C'), 
(4, 1004, 'User D'), 
(5, 1005, 'User E'), 
(6, 1006, 'User F'); 


CREATE TABLE IF NOT EXISTS `tbl_userscores` (
    `fbuid` bigint(20) NOT NULL, 
    `game_id` varchar(255) NOT NULL, 
    `score1` bigint(20) NOT NULL default '0', 
    `score2` bigint(20) NOT NULL default '0', 
    `score3` bigint(20) NOT NULL default '0', 
    `score4` bigint(20) NOT NULL default '0', 
    `created_date` datetime NOT NULL, 
    `updated_date` datetime NOT NULL, 
    PRIMARY KEY (`game_id`), 
    UNIQUE KEY `fbuid` (`fbuid`,`game_id`), 
    KEY `fbuid_2` (`fbuid`,`game_id`,`score4`), 
    KEY `fbuid_3` (`fbuid`,`game_id`,`score4`,`updated_date`), 
    KEY `fbuid_4` (`fbuid`,`game_id`,`score1`,`score2`,`score3`,`score4`,`created_date`,`updated_date`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

INSERT INTO `tbl_userscores` (`fbuid`, `game_id`, `score1`, `score2`, `score3`, `score4`, `created_date`, `updated_date`) VALUES 
(1001, '13361975565253060', 650, 3300, 7675, 14500, '2012-05-05 13:59:55', '2012-05-05 14:01:50'), 
(1001, '1336278398787510', 3100, 87725, 326675, 573625, '2012-05-06 12:28:20', '2012-05-06 12:33:27'), 
(1001, '13368015862343980', 12875, 82550, 158625, 299550, '2012-05-12 13:48:08', '2012-05-12 13:53:15'), 
(1001, '13369691453105020', 7925, 58525, 283100, 368225, '2012-05-14 12:20:47', '2012-05-14 12:25:54'), 
(1002, '1336328839124400', 1275, 11475, 31450, 50475, '2012-05-07 02:27:34', '2012-05-07 02:28:20'), 
(1002, '13363686059958120', 11025, 48900, 72725, 115150, '2012-05-07 13:30:21', '2012-05-07 13:31:07'), 
(1002, '13364088902032830', 6650, 6700, 10200, 17625, '2012-05-08 00:41:46', '2012-05-08 00:42:32'), 
(1002, '13364910479425300', 3600, 17050, 60450, 114800, '2012-05-08 23:31:03', '2012-05-08 23:31:49'), 
(1002, '13364949763272710', 17250, 168125, 479475, 596925, '2012-05-07 00:37:33', '2012-05-07 00:41:21'), 
(1003, '13363240964199380', 84150, 84150, 84150, 84150, '2012-05-07 01:11:37', '2012-05-07 01:12:22'), 
(1003, '1336465518338010', 297275, 351300, 437150, 468350, '2012-05-08 16:31:52', '2012-05-08 16:32:38'), 
(1003, '13368122913207860', 0, 82350, 94150, 102750, '2012-05-12 16:45:20', '2012-05-12 16:48:09'), 
(1003, '13368125091164060', 423925, 428125, 521875, 589750, '2012-05-12 16:54:00', '2012-05-12 16:54:47'), 
(1004, '13363118226930570', 3275, 10975, 16250, 22900, '2012-05-06 21:43:58', '2012-05-06 21:44:43'), 
(1004, '13366228756934380', 23275, 149100, 380600, 382075, '2012-05-10 12:08:46', '2012-05-10 12:10:49'), 
(1004, '13366232802957960', 3650, 23525, 49975, 49975, '2012-05-10 12:14:55', '2012-05-10 12:15:42'), 
(1005, '13361215491096720', 1200, 16250, 39125, 55800, '2012-05-04 16:52:59', '2012-05-04 16:54:29'), 
(1005, '13361216729657120', 11000, 29800, 82575, 188550, '2012-05-04 16:55:03', '2012-05-04 16:56:33'), 
(1005, '13361364491988250', 6925, 50925, 89100, 180425, '2012-05-04 21:01:12', '2012-05-04 21:02:43'), 
(1005, '13362204979150640', 11300, 39800, 63675, 78725, '2012-05-05 20:22:08', '2012-05-05 20:23:36'), 
(1005, '13362311869003160', 11575, 61500, 134200, 233600, '2012-05-05 23:20:17', '2012-05-05 23:21:48'), 
(1005, '133628163373910', 3500, 40175, 131375, 251725, '2012-05-06 13:21:03', '2012-05-06 13:22:35'), 
(1006, '13361224889844730', 6700, 30575, 49650, 50475, '2012-05-04 17:08:24', '2012-05-04 17:09:10'), 
(1006, '13366294182421110', 16800, 87675, 119150, 206500, '2012-05-10 13:57:42', '2012-05-10 14:00:15'), 
(1006, '13366296357158010', 23050, 99025, 229075, 381925, '2012-05-10 14:01:27', '2012-05-10 14:03:58'), 
(1006, '13368319289949330', 22975, 130375, 350600, 355150, '2012-05-12 22:13:00', '2012-05-12 22:15:08'); 

위 데이터를 사용하여 주간 최고 기록을 얻으려면 아래의 sql을 사용합니다.

SELECT U1.fbuid, U1.fullname, U2.score4 AS weeklyhighscore, U2.created_date, U2.updated_date, TIMEDIFF(U2.updated_date, U2.created_date) AS Duration 
    FROM tbl_user AS U1, ( 
       SELECT fbuid, score4, MIN(updated_date) AS updated_date, created_date 
       FROM tbl_userscores AS A 
       WHERE A.score4 
       IN (
        SELECT MAX( `score4`) AS best 
        FROM tbl_userscores AS B 
        WHERE A.fbuid = B.fbuid 
        AND B.score1 >0 
        AND B.score2 >0 
        AND B.score3 >0 
        AND B.score4 >0 
        AND `updated_date` >= '2012-05-06 00:00:00' AND `updated_date` <= '2012-05-12 23:59:59' 
        GROUP BY fbuid 
       ) 
       GROUP BY A.fbuid 
       ORDER BY `A`.`score4` DESC , updated_date ASC 
      ) AS U2 
WHERE U1.fbuid = U2.fbuid 
ORDER BY weeklyhighscore DESC 
LIMIT 0 , 30 

예상 결과 :

+-------+----------+-----------------+---------------------+---------------------+----------+ 
| fbuid | fullname | weeklyhighscore | created_date  | updated_date  | Duration | 
| 1002 | User B | 596925   | 2012-05-07 00:37:33 | 2012-05-07 00:41:21 | 00:03:48 | 
| 1003 | User C | 589750   | 2012-05-12 16:54:00 | 2012-05-12 16:54:47 | 00:00:47 | 
| 1001 | User A | 573625   | 2012-05-06 12:28:20 | 2012-05-06 12:33:27 | 00:05:07 | 
| 1004 | User D | 382075   | 2012-05-10 12:08:46 | 2012-05-10 12:10:49 | 00:02:03 | 
| 1006 | User F | 381925   | 2012-05-10 14:01:27 | 2012-05-10 14:03:58 | 00:02:31 | 
| 1005 | User E | 251725   | 2012-05-06 13:21:03 | 2012-05-06 13:22:35 | 00:01:32 | 
+-------+----------+-----------------+---------------------+---------------------+----------+ 

나는 두 개의 테이블, tbl_user 및 tbl_userscores 있습니다. 사용자가 게임을 할 때마다 점수 1에서 점수 4 (점수 4 세션, 최종 점수 4)로 시간을 절약 할 수 있습니다.

tbl_userscores는 (fbuid, score4, updated_date, create_date)로 색인 생성되었습니다. 45K 레코드를 보유하고 있으며 계속 성장하고 있습니다.

나는 주간지 상위 30 위권을 얻고 싶다. 이 쿼리를 완료하려면 평균 45 초가 걸렸습니다.

그래서 나는 그것을 더 잘 만드는 방법에 대한 전문가의 조언을 구합니다.

미리 감사드립니다.

+0

일반적 경험 법칙 : JOIN 또는 WHERE 절에 사용 된 모든 필드에는 인덱스가 있어야합니다. –

+0

Marc에게 감사합니다. score1, score2 및 score3를 함께 색인 한 결과 쿼리에 18.7836 초가 걸렸습니다. 아직도 개선을위한 방이 있습니까? – MFei

+0

@MFei이 쿼리를 시도해야합니다 .... –

답변

0

사용자 당 최대 (점수 4)를 추출하는 상관 하위 쿼리에서 대부분의 시간이 소요된다고 생각합니다. 한 번에 상위 30 개 점수를 얻고 메인 테이블에 대한 필터로 사용되도록 재구성 될 수 있습니다. 불행히도 중복을 피할 수 있고 업데이트 된 날짜를 가장 먼저 취해야 할 필요가 있으므로이 필터를 가져 오기위한 추가 파생 테이블이 있습니다. 이것이 가장 느린 부분 인 경우 minUpdated 파생 테이블을 제거하고 전체 쿼리를 포함하고 not exists을 사용하여 score4 당 최소 updated_date가있는 레코드 만 선택할 수 있습니다. 당신이 tipically 30 비트 이상의 비트가있을 것 입니다이 빨리해야합니다. 더 유망한 패턴> = 및 <와

SELECT U1.fbuid, 
     U1.fullname, 
     U2.score4 AS weeklyhighscore, 
     U2.created_date, 
     U2.updated_date, 
     TIMEDIFF(U2.updated_date, U2.created_date) AS Duration 
FROM tbl_user AS U1 
INNER JOIN tbl_userscores U2 
    ON U1.FbUid = U2.FbUid 
/* Top 30 scores by user */ 
INNER JOIN 
(
    SELECT B.fbuid, 
     MAX(`score4`) AS best 
    FROM tbl_userscores AS B 
    WHERE B.score1 > 0 
    AND B.score2 > 0 
    AND B.score3 > 0 
    AND B.score4 > 0 
    AND `updated_date` >= '2012-05-06 00:00:00' 
    AND `updated_date` < '2012-05-13 00:00:00' 
    GROUP BY fbuid 
    ORDER BY best DESC 
    LIMIT 30 
) A 
    ON U2.FbUid = A.FbUid 
    AND U2.Score4 = best 
/* Filter by min(updated_date) in case of several same scores per user */ 
INNER JOIN 
(
    SELECT FbUid, Score4, MIN(updated_date) updated_date 
    FROM tbl_userscores 
    GROUP BY FbUid, Score4 
) minUpdated 
    ON U2.FbUid = minUpdated.FbUid 
    AND U2.Score4 = minUpdated.Score4 
    AND U2.Updated_date = minUpdated.Updated_date 
ORDER BY weeklyhighscore DESC 

내가 대체 한 날짜 비교. 이 변경으로 인해 datetime 해결 문제가 발생하지 않습니다. 마지막 999 밀리 초 동안 업데이트가 있으면 레코드가 손실 될 수 있습니다. 이것은 또한 훌륭한 방어 도구입니다 - 누군가가 어떻게 든 비즈니스 로직이 기대하지 않는 날짜의 시간 부분을 입력하는 것을 관리하더라도 쿼리가 작동합니다.

+0

답장을 보내 주셔서 감사합니다 Nikola, 답장을 보내 주셨습니다. 테스트 해 보았지만 주간 최고 기록과 사용자도 잘못 표시되었습니다. :( – MFei

+0

죄송합니다 Nikola, 내가 편집 한 위의 데이터로 임시 데이터베이스를 만든 후에 올바른 정보를 보여줍니다. 데이터가 잘못되었습니다. 어떤 생각이 있습니까? – MFei

+0

좋아, 네게 무슨 문제가 있는지 알았어. "ORDER BY"에 대한 DESC가 필요해. 최고 기록을 얻기 위해 두 번째 내적 조인에서 "최고"를 얻습니다. – MFei

관련 문제