首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

MySQL 隨機抽取角色名稱與游標處理離線玩家發獎實戰

     編輯:MySQL 綜合教學

遊戲伺服器端隨機命名與批量離線發獎:MySQL 隨機查詢與游標進階應用

在遊戲開發中,角色隨機命名與離線玩家發獎是常見需求。本文分享兩個實戰案例:利用 RAND() 高效抽取未使用名稱,以及透過游標批量處理百萬級玩家資料。

案例一:高效隨機抽取未重複角色名稱

需求: 從預先建立的 names 表中隨機挑選一個符合性別且未被使用的名稱。

表結構:

CREATE TABLE names (
  id INT PRIMARY KEY AUTO_INCREMENT,
  rname VARCHAR(50),
  sex TINYINT  -- 1 男 2 女
);

存儲過程實現:

CREATE PROCEDURE GetRandomName(
  IN _sex TINYINT,
  IN _world INT,
  OUT _name VARCHAR(50),
  OUT returnvalue INT
)
BEGIN
  DECLARE randnum INT DEFAULT 0;
  -- 取得隨機起始點(假設表約 30 萬筆)
  SELECT FLOOR(RAND() * 309034) INTO randnum;

  -- 從隨機點向後查找第一個符合條件的名稱
  SELECT rname INTO _name
  FROM names
  WHERE sex = _sex
    AND rname NOT IN (SELECT Name FROM longwen.player WHERE WorldID = _world)
    AND id > randnum
  LIMIT 1;

  SET returnvalue = 0;
END

優化說明:

  • 使用 id > randnum 避免 ORDER BY RAND() 全表掃描,效率提升數十倍。
  • 若未找到,可再補一輪 id <= randnum 的查詢,確保必定取得結果。

案例二:游標批量給離線玩家發送郵件獎勵

需求: 維護期間需給所有玩家發放補償,包含離線玩家,直接操作資料庫。

初版錯誤寫法(只能處理一筆):

DECLARE _cursor CURSOR FOR SELECT RoleID FROM player;
REPEAT
  FETCH _cursor INTO _roleId;
  -- 錯誤:在迴圈內再執行 SELECT 會導致游標狀態混亂
  SELECT ...; 
  REPLACE INTO email(roleID, datas) VALUES(_roleId, 'test');
UNTIL _done END REPEAT;

正確寫法(將查詢移至游標宣告):

CREATE PROCEDURE SendOfflineRewards()
BEGIN
  DECLARE _roleId BIGINT;
  DECLARE _done INT DEFAULT 0;

  -- 游標直接查詢需發獎的玩家(排除已有郵件者)
  DECLARE _cursor CURSOR FOR
    SELECT RoleID FROM player
    WHERE RoleID NOT IN (SELECT roleID FROM email WHERE LENGTH(datas) <> 0);

  -- 捕獲「無資料」狀態 (SQLSTATE '02000')
  DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET _done = 1;

  OPEN _cursor;
  SET _done = 0;

  REPEAT
    FETCH _cursor INTO _roleId;
    IF NOT _done THEN
      REPLACE INTO email(roleID, datas) VALUES(_roleId, 'test');
    END IF;
  UNTIL _done END REPEAT;

  CLOSE _cursor;
END

SQLSTATE '02000' 三種觸發條件

  1. SELECT INTO 或子查詢結果為空表
  2. UPDATE/DELETE 影響行數為零
  3. FETCH 游標超過結果集最後一行

理解這三點,才能正確設計游標結束條件,避免漏處理或無限迴圈。

經驗總結

  • 大量資料隨機抽樣:id > RAND()*MAX_ID + LIMIT 1 遠優於 ORDER BY RAND()。
  • 游標查詢務必在 DECLARE CURSOR 完成,迴圈內只做 FETCH 與業務邏輯。
  • 批量寫入建議分批提交(如每 5000 筆 COMMIT),避免長事務鎖表。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved