使用MySQL时SUB QUERY,LIMIT和ORDER BY的性能注意事项

时间:2015-10-20 17:03:51

标签: mysql sql performance subquery sql-limit

目标:选择正在进行的游戏的10个用户< 5。

方法1:在MySQL中做所有事情

选择用户(LIMIT 10)并检查每个用户的n_ongoingGames

方法2:SQL +结果集分析

获取30个用户的记录。 对于每条记录,再次转到db并检查n_ongoingGames。假设每个用户的概率(n_ongoingGames> 5)为50%,我们需要检查20条记录。

-- Approach 1: Do everything within MySQL
-- --------------------------------------
SELECT u.*
FROM USERS u
WHERE 
    ( -- n_ongoingGames for user < 5
        (
            SELECT COUNT(gameID) AS n_ongoingGames
            FROM games g
            WHERE 
                (g.player1_userID = u.userID) OR 
                (g.player2_userID = u.userID) OR
                (g.player3_userID = u.userID) OR
                ...
                ...
                ...
                (g.player10_userID = u.userID)
        ) < 5
    ) AND
    (u.cash_balance > 500)
ORDER BY u.user_rating
LIMIT 10;


-- Approach 2: SQL + result-set analysis
-- -------------------------------------
SELECT u.*
FROM USERS u
WHERE
    (u.cash_balance > 500)
ORDER BY u.user_rating
LIMIT 30;

问题:

  1. 在方法1中,MySQL是否为users表中的每个用户检查(n_ongoingGames为用户&lt; 5)?
  2. 哪种方法更快?
  3. 如果只需要1个用户而不是10个(LIMIT 1),它会有所不同(更快的方法)
  4. 感谢。

1 个答案:

答案 0 :(得分:3)

我建议以下内容,假设用户不能同时为两个玩家:

SELECT u.*
FROM USERS u
WHERE u.cash_balance > 500 AND
      ((SELECT COUNT(*) AS n_ongoingGames
        FROM games g
        WHERE g.player1_userID = u.userID
       ) +
       (SELECT COUNT(*) AS n_ongoingGames
        FROM games g
        WHERE g.player2_userID = u.userID
       )
      ) < 5
ORDER BY u.user_rating
LIMIT 10;

使用以下索引:games(player1_userID)games(player2_userID)。您还需要一个关于用户的索引;一种可能性是users(user_rating, cash_balance),但我认为MySQL不够智能,无法使用索引扫描表。你可能不得不接受users(cash_balance)

games()上的索引意味着可以在索引中满足计数。这应该是一种特别快速的计数类型。如果您删除现金余额的条件,那么users(user_rating)上的索引应该会使查询非常快。