mirror of
https://github.com/hykilpikonna/AquaDX.git
synced 2026-09-13 11:55:39 -05:00
[O] Ranking optimizations
This commit is contained in:
@@ -69,10 +69,18 @@ abstract class GameApiController<T : IUserData>(val name: String, userDataClass:
|
||||
fun rankingCacheInit() = thread { rankingCacheRun() }
|
||||
|
||||
// Every 20 minutes
|
||||
@Scheduled(fixedRate = 20, timeUnit = TimeUnit.MINUTES)
|
||||
@Scheduled(fixedRate = 20, initialDelay = 20, timeUnit = TimeUnit.MINUTES)
|
||||
fun rankingCacheRun() = rankingCacheLock.maybeLock { rankingCacheCompute() }
|
||||
|
||||
private val tableName = when (name) { "mai2" -> "maimai2"; "chu3" -> "chusan"; else -> name }
|
||||
private val userDataTable = when (name) {
|
||||
"mai2" -> "maimai2_user_detail"
|
||||
"chu3" -> "chusan_user_data"
|
||||
"ongeki" -> "ongeki_user_data"
|
||||
else -> "wacca_user"
|
||||
}
|
||||
private val userCardColumn = if (name == "chu3") "card_id" else "aime_card_id"
|
||||
|
||||
fun rankingCacheCompute() {
|
||||
val time = millis()
|
||||
rankingCache = us.em.createNativeQuery(
|
||||
@@ -82,20 +90,21 @@ abstract class GameApiController<T : IUserData>(val name: String, userDataClass:
|
||||
u.user_name,
|
||||
${if (name == "ongeki") "u.new_player_rating" else "u.player_rating"} AS rating,
|
||||
u.last_play_date,
|
||||
AVG(p.achievement) / 10000.0 AS acc,
|
||||
SUM(p.is_full_combo) AS fc,
|
||||
SUM(p.is_all_perfect) AS ap,
|
||||
r.achievement_sum / NULLIF(r.play_count, 0) / 10000.0 AS acc,
|
||||
r.full_combo_count AS fc,
|
||||
r.all_perfect_count AS ap,
|
||||
c.ranking_banned or COALESCE(a.opt_out_of_leaderboard, 0) or c.status = 12 AS hide,
|
||||
a.username
|
||||
FROM ${tableName}_user_playlog_view p
|
||||
JOIN ${tableName}_user_data_view u ON p.user_id = u.id
|
||||
JOIN sega_card c ON u.aime_card_id = c.id
|
||||
FROM ${tableName}_user_ranking_cache r
|
||||
JOIN $userDataTable u ON r.user_id = u.id
|
||||
JOIN sega_card c ON u.$userCardColumn = c.id
|
||||
LEFT JOIN aqua_net_user a ON c.net_user_id = a.au_id
|
||||
GROUP BY p.user_id, u.player_rating
|
||||
HAVING NOT hide ${if (name == "ongeki") "AND rating > 0" else "" /* Hide users on Ongeki 1.45 and below */}
|
||||
WHERE r.play_count > 0
|
||||
AND NOT (c.ranking_banned or COALESCE(a.opt_out_of_leaderboard, 0) or c.status = 12)
|
||||
${if (name == "ongeki") "AND u.new_player_rating > 0" else "" /* Hide users on Ongeki 1.45 and below */}
|
||||
ORDER BY rating DESC;
|
||||
"""
|
||||
).exec.mapIndexed { i, it ->
|
||||
).setHint("jakarta.persistence.query.timeout", 60_000).exec.mapIndexed { i, it ->
|
||||
GenericRankingPlayer(
|
||||
rank = i + 1,
|
||||
id = it[0]!!.long,
|
||||
|
||||
309
src/main/resources/db/120/V1000_87__ranking_cache.sql
Normal file
309
src/main/resources/db/120/V1000_87__ranking_cache.sql
Normal file
@@ -0,0 +1,309 @@
|
||||
-- Ranking previously aggregated every playlog every 20 minutes. Keep exact,
|
||||
-- disposable aggregates in game-specific cache tables with real foreign keys.
|
||||
CREATE TABLE maimai2_user_ranking_cache
|
||||
(
|
||||
user_id BIGINT NOT NULL,
|
||||
achievement_sum BIGINT NOT NULL DEFAULT 0,
|
||||
play_count BIGINT NOT NULL DEFAULT 0,
|
||||
full_combo_count BIGINT NOT NULL DEFAULT 0,
|
||||
all_perfect_count BIGINT NOT NULL DEFAULT 0,
|
||||
CONSTRAINT pk_maimai2_user_ranking_cache PRIMARY KEY (user_id),
|
||||
CONSTRAINT fk_maimai2_user_ranking_cache_user FOREIGN KEY (user_id)
|
||||
REFERENCES maimai2_user_detail (id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE chusan_user_ranking_cache
|
||||
(
|
||||
user_id BIGINT NOT NULL,
|
||||
achievement_sum BIGINT NOT NULL DEFAULT 0,
|
||||
play_count BIGINT NOT NULL DEFAULT 0,
|
||||
full_combo_count BIGINT NOT NULL DEFAULT 0,
|
||||
all_perfect_count BIGINT NOT NULL DEFAULT 0,
|
||||
CONSTRAINT pk_chusan_user_ranking_cache PRIMARY KEY (user_id),
|
||||
CONSTRAINT fk_chusan_user_ranking_cache_user FOREIGN KEY (user_id)
|
||||
REFERENCES chusan_user_data (id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE ongeki_user_ranking_cache
|
||||
(
|
||||
user_id BIGINT NOT NULL,
|
||||
achievement_sum BIGINT NOT NULL DEFAULT 0,
|
||||
play_count BIGINT NOT NULL DEFAULT 0,
|
||||
full_combo_count BIGINT NOT NULL DEFAULT 0,
|
||||
all_perfect_count BIGINT NOT NULL DEFAULT 0,
|
||||
CONSTRAINT pk_ongeki_user_ranking_cache PRIMARY KEY (user_id),
|
||||
CONSTRAINT fk_ongeki_user_ranking_cache_user FOREIGN KEY (user_id)
|
||||
REFERENCES ongeki_user_data (id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE wacca_user_ranking_cache
|
||||
(
|
||||
user_id BIGINT NOT NULL,
|
||||
achievement_sum BIGINT NOT NULL DEFAULT 0,
|
||||
play_count BIGINT NOT NULL DEFAULT 0,
|
||||
full_combo_count BIGINT NOT NULL DEFAULT 0,
|
||||
all_perfect_count BIGINT NOT NULL DEFAULT 0,
|
||||
CONSTRAINT pk_wacca_user_ranking_cache PRIMARY KEY (user_id),
|
||||
CONSTRAINT fk_wacca_user_ranking_cache_user FOREIGN KEY (user_id)
|
||||
REFERENCES wacca_user (id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
INSERT INTO maimai2_user_ranking_cache
|
||||
(user_id, achievement_sum, play_count, full_combo_count, all_perfect_count)
|
||||
SELECT
|
||||
user_id,
|
||||
SUM(achievement),
|
||||
COUNT(*),
|
||||
SUM(IF(max_combo = total_combo, 1, 0)),
|
||||
SUM(IF(
|
||||
(tap_miss + tap_good + tap_great = 0) AND
|
||||
(hold_miss + hold_good + hold_great = 0) AND
|
||||
(slide_miss + slide_good + slide_great = 0) AND
|
||||
(touch_miss + touch_good + touch_great = 0) AND
|
||||
(break_miss + break_good + break_great = 0),
|
||||
1, 0
|
||||
))
|
||||
FROM maimai2_user_playlog
|
||||
GROUP BY user_id;
|
||||
|
||||
INSERT INTO chusan_user_ranking_cache
|
||||
(user_id, achievement_sum, play_count, full_combo_count, all_perfect_count)
|
||||
SELECT user_id, SUM(score), COUNT(*), SUM(is_full_combo), SUM(is_all_justice)
|
||||
FROM chusan_user_playlog
|
||||
GROUP BY user_id;
|
||||
|
||||
INSERT INTO ongeki_user_ranking_cache
|
||||
(user_id, achievement_sum, play_count, full_combo_count, all_perfect_count)
|
||||
SELECT user_id, SUM(tech_score), COUNT(*), SUM(is_full_combo), SUM(is_all_break)
|
||||
FROM ongeki_user_playlog
|
||||
GROUP BY user_id;
|
||||
|
||||
INSERT INTO wacca_user_ranking_cache
|
||||
(user_id, achievement_sum, play_count, full_combo_count, all_perfect_count)
|
||||
SELECT user_id, SUM(achievement), COUNT(*), SUM(is_full_combo), SUM(is_all_perfect)
|
||||
FROM wacca_user_playlog
|
||||
GROUP BY user_id;
|
||||
|
||||
CREATE TRIGGER trg_maimai2_rank_insert
|
||||
AFTER INSERT ON maimai2_user_playlog
|
||||
FOR EACH ROW
|
||||
INSERT INTO maimai2_user_ranking_cache
|
||||
(user_id, achievement_sum, play_count, full_combo_count, all_perfect_count)
|
||||
VALUES
|
||||
(NEW.user_id, NEW.achievement, 1,
|
||||
IF(NEW.max_combo = NEW.total_combo, 1, 0),
|
||||
IF(
|
||||
(NEW.tap_miss + NEW.tap_good + NEW.tap_great = 0) AND
|
||||
(NEW.hold_miss + NEW.hold_good + NEW.hold_great = 0) AND
|
||||
(NEW.slide_miss + NEW.slide_good + NEW.slide_great = 0) AND
|
||||
(NEW.touch_miss + NEW.touch_good + NEW.touch_great = 0) AND
|
||||
(NEW.break_miss + NEW.break_good + NEW.break_great = 0),
|
||||
1, 0
|
||||
))
|
||||
ON DUPLICATE KEY UPDATE
|
||||
achievement_sum = achievement_sum + NEW.achievement,
|
||||
play_count = play_count + 1,
|
||||
full_combo_count = full_combo_count + IF(NEW.max_combo = NEW.total_combo, 1, 0),
|
||||
all_perfect_count = all_perfect_count + IF(
|
||||
(NEW.tap_miss + NEW.tap_good + NEW.tap_great = 0) AND
|
||||
(NEW.hold_miss + NEW.hold_good + NEW.hold_great = 0) AND
|
||||
(NEW.slide_miss + NEW.slide_good + NEW.slide_great = 0) AND
|
||||
(NEW.touch_miss + NEW.touch_good + NEW.touch_great = 0) AND
|
||||
(NEW.break_miss + NEW.break_good + NEW.break_great = 0),
|
||||
1, 0
|
||||
);
|
||||
|
||||
CREATE TRIGGER trg_maimai2_rank_delete
|
||||
AFTER DELETE ON maimai2_user_playlog
|
||||
FOR EACH ROW
|
||||
UPDATE maimai2_user_ranking_cache SET
|
||||
achievement_sum = achievement_sum - OLD.achievement,
|
||||
play_count = play_count - 1,
|
||||
full_combo_count = full_combo_count - IF(OLD.max_combo = OLD.total_combo, 1, 0),
|
||||
all_perfect_count = all_perfect_count - IF(
|
||||
(OLD.tap_miss + OLD.tap_good + OLD.tap_great = 0) AND
|
||||
(OLD.hold_miss + OLD.hold_good + OLD.hold_great = 0) AND
|
||||
(OLD.slide_miss + OLD.slide_good + OLD.slide_great = 0) AND
|
||||
(OLD.touch_miss + OLD.touch_good + OLD.touch_great = 0) AND
|
||||
(OLD.break_miss + OLD.break_good + OLD.break_great = 0),
|
||||
1, 0
|
||||
)
|
||||
WHERE user_id = OLD.user_id;
|
||||
|
||||
CREATE TRIGGER trg_maimai2_rank_update_remove
|
||||
AFTER UPDATE ON maimai2_user_playlog
|
||||
FOR EACH ROW
|
||||
UPDATE maimai2_user_ranking_cache SET
|
||||
achievement_sum = achievement_sum - OLD.achievement,
|
||||
play_count = play_count - 1,
|
||||
full_combo_count = full_combo_count - IF(OLD.max_combo = OLD.total_combo, 1, 0),
|
||||
all_perfect_count = all_perfect_count - IF(
|
||||
(OLD.tap_miss + OLD.tap_good + OLD.tap_great = 0) AND
|
||||
(OLD.hold_miss + OLD.hold_good + OLD.hold_great = 0) AND
|
||||
(OLD.slide_miss + OLD.slide_good + OLD.slide_great = 0) AND
|
||||
(OLD.touch_miss + OLD.touch_good + OLD.touch_great = 0) AND
|
||||
(OLD.break_miss + OLD.break_good + OLD.break_great = 0),
|
||||
1, 0
|
||||
)
|
||||
WHERE user_id = OLD.user_id;
|
||||
|
||||
CREATE TRIGGER trg_maimai2_rank_update_add
|
||||
AFTER UPDATE ON maimai2_user_playlog
|
||||
FOR EACH ROW FOLLOWS trg_maimai2_rank_update_remove
|
||||
INSERT INTO maimai2_user_ranking_cache
|
||||
(user_id, achievement_sum, play_count, full_combo_count, all_perfect_count)
|
||||
VALUES
|
||||
(NEW.user_id, NEW.achievement, 1,
|
||||
IF(NEW.max_combo = NEW.total_combo, 1, 0),
|
||||
IF(
|
||||
(NEW.tap_miss + NEW.tap_good + NEW.tap_great = 0) AND
|
||||
(NEW.hold_miss + NEW.hold_good + NEW.hold_great = 0) AND
|
||||
(NEW.slide_miss + NEW.slide_good + NEW.slide_great = 0) AND
|
||||
(NEW.touch_miss + NEW.touch_good + NEW.touch_great = 0) AND
|
||||
(NEW.break_miss + NEW.break_good + NEW.break_great = 0),
|
||||
1, 0
|
||||
))
|
||||
ON DUPLICATE KEY UPDATE
|
||||
achievement_sum = achievement_sum + NEW.achievement,
|
||||
play_count = play_count + 1,
|
||||
full_combo_count = full_combo_count + IF(NEW.max_combo = NEW.total_combo, 1, 0),
|
||||
all_perfect_count = all_perfect_count + IF(
|
||||
(NEW.tap_miss + NEW.tap_good + NEW.tap_great = 0) AND
|
||||
(NEW.hold_miss + NEW.hold_good + NEW.hold_great = 0) AND
|
||||
(NEW.slide_miss + NEW.slide_good + NEW.slide_great = 0) AND
|
||||
(NEW.touch_miss + NEW.touch_good + NEW.touch_great = 0) AND
|
||||
(NEW.break_miss + NEW.break_good + NEW.break_great = 0),
|
||||
1, 0
|
||||
);
|
||||
|
||||
CREATE TRIGGER trg_chusan_rank_insert
|
||||
AFTER INSERT ON chusan_user_playlog
|
||||
FOR EACH ROW
|
||||
INSERT INTO chusan_user_ranking_cache
|
||||
(user_id, achievement_sum, play_count, full_combo_count, all_perfect_count)
|
||||
VALUES (NEW.user_id, NEW.score, 1, NEW.is_full_combo, NEW.is_all_justice)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
achievement_sum = achievement_sum + NEW.score,
|
||||
play_count = play_count + 1,
|
||||
full_combo_count = full_combo_count + NEW.is_full_combo,
|
||||
all_perfect_count = all_perfect_count + NEW.is_all_justice;
|
||||
|
||||
CREATE TRIGGER trg_chusan_rank_delete
|
||||
AFTER DELETE ON chusan_user_playlog
|
||||
FOR EACH ROW
|
||||
UPDATE chusan_user_ranking_cache SET
|
||||
achievement_sum = achievement_sum - OLD.score,
|
||||
play_count = play_count - 1,
|
||||
full_combo_count = full_combo_count - OLD.is_full_combo,
|
||||
all_perfect_count = all_perfect_count - OLD.is_all_justice
|
||||
WHERE user_id = OLD.user_id;
|
||||
|
||||
CREATE TRIGGER trg_chusan_rank_update_remove
|
||||
AFTER UPDATE ON chusan_user_playlog
|
||||
FOR EACH ROW
|
||||
UPDATE chusan_user_ranking_cache SET
|
||||
achievement_sum = achievement_sum - OLD.score,
|
||||
play_count = play_count - 1,
|
||||
full_combo_count = full_combo_count - OLD.is_full_combo,
|
||||
all_perfect_count = all_perfect_count - OLD.is_all_justice
|
||||
WHERE user_id = OLD.user_id;
|
||||
|
||||
CREATE TRIGGER trg_chusan_rank_update_add
|
||||
AFTER UPDATE ON chusan_user_playlog
|
||||
FOR EACH ROW FOLLOWS trg_chusan_rank_update_remove
|
||||
INSERT INTO chusan_user_ranking_cache
|
||||
(user_id, achievement_sum, play_count, full_combo_count, all_perfect_count)
|
||||
VALUES (NEW.user_id, NEW.score, 1, NEW.is_full_combo, NEW.is_all_justice)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
achievement_sum = achievement_sum + NEW.score,
|
||||
play_count = play_count + 1,
|
||||
full_combo_count = full_combo_count + NEW.is_full_combo,
|
||||
all_perfect_count = all_perfect_count + NEW.is_all_justice;
|
||||
|
||||
CREATE TRIGGER trg_ongeki_rank_insert
|
||||
AFTER INSERT ON ongeki_user_playlog
|
||||
FOR EACH ROW
|
||||
INSERT INTO ongeki_user_ranking_cache
|
||||
(user_id, achievement_sum, play_count, full_combo_count, all_perfect_count)
|
||||
VALUES (NEW.user_id, NEW.tech_score, 1, NEW.is_full_combo, NEW.is_all_break)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
achievement_sum = achievement_sum + NEW.tech_score,
|
||||
play_count = play_count + 1,
|
||||
full_combo_count = full_combo_count + NEW.is_full_combo,
|
||||
all_perfect_count = all_perfect_count + NEW.is_all_break;
|
||||
|
||||
CREATE TRIGGER trg_ongeki_rank_delete
|
||||
AFTER DELETE ON ongeki_user_playlog
|
||||
FOR EACH ROW
|
||||
UPDATE ongeki_user_ranking_cache SET
|
||||
achievement_sum = achievement_sum - OLD.tech_score,
|
||||
play_count = play_count - 1,
|
||||
full_combo_count = full_combo_count - OLD.is_full_combo,
|
||||
all_perfect_count = all_perfect_count - OLD.is_all_break
|
||||
WHERE user_id = OLD.user_id;
|
||||
|
||||
CREATE TRIGGER trg_ongeki_rank_update_remove
|
||||
AFTER UPDATE ON ongeki_user_playlog
|
||||
FOR EACH ROW
|
||||
UPDATE ongeki_user_ranking_cache SET
|
||||
achievement_sum = achievement_sum - OLD.tech_score,
|
||||
play_count = play_count - 1,
|
||||
full_combo_count = full_combo_count - OLD.is_full_combo,
|
||||
all_perfect_count = all_perfect_count - OLD.is_all_break
|
||||
WHERE user_id = OLD.user_id;
|
||||
|
||||
CREATE TRIGGER trg_ongeki_rank_update_add
|
||||
AFTER UPDATE ON ongeki_user_playlog
|
||||
FOR EACH ROW FOLLOWS trg_ongeki_rank_update_remove
|
||||
INSERT INTO ongeki_user_ranking_cache
|
||||
(user_id, achievement_sum, play_count, full_combo_count, all_perfect_count)
|
||||
VALUES (NEW.user_id, NEW.tech_score, 1, NEW.is_full_combo, NEW.is_all_break)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
achievement_sum = achievement_sum + NEW.tech_score,
|
||||
play_count = play_count + 1,
|
||||
full_combo_count = full_combo_count + NEW.is_full_combo,
|
||||
all_perfect_count = all_perfect_count + NEW.is_all_break;
|
||||
|
||||
CREATE TRIGGER trg_wacca_rank_insert
|
||||
AFTER INSERT ON wacca_user_playlog
|
||||
FOR EACH ROW
|
||||
INSERT INTO wacca_user_ranking_cache
|
||||
(user_id, achievement_sum, play_count, full_combo_count, all_perfect_count)
|
||||
VALUES (NEW.user_id, NEW.achievement, 1, NEW.is_full_combo, NEW.is_all_perfect)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
achievement_sum = achievement_sum + NEW.achievement,
|
||||
play_count = play_count + 1,
|
||||
full_combo_count = full_combo_count + NEW.is_full_combo,
|
||||
all_perfect_count = all_perfect_count + NEW.is_all_perfect;
|
||||
|
||||
CREATE TRIGGER trg_wacca_rank_delete
|
||||
AFTER DELETE ON wacca_user_playlog
|
||||
FOR EACH ROW
|
||||
UPDATE wacca_user_ranking_cache SET
|
||||
achievement_sum = achievement_sum - OLD.achievement,
|
||||
play_count = play_count - 1,
|
||||
full_combo_count = full_combo_count - OLD.is_full_combo,
|
||||
all_perfect_count = all_perfect_count - OLD.is_all_perfect
|
||||
WHERE user_id = OLD.user_id;
|
||||
|
||||
CREATE TRIGGER trg_wacca_rank_update_remove
|
||||
AFTER UPDATE ON wacca_user_playlog
|
||||
FOR EACH ROW
|
||||
UPDATE wacca_user_ranking_cache SET
|
||||
achievement_sum = achievement_sum - OLD.achievement,
|
||||
play_count = play_count - 1,
|
||||
full_combo_count = full_combo_count - OLD.is_full_combo,
|
||||
all_perfect_count = all_perfect_count - OLD.is_all_perfect
|
||||
WHERE user_id = OLD.user_id;
|
||||
|
||||
CREATE TRIGGER trg_wacca_rank_update_add
|
||||
AFTER UPDATE ON wacca_user_playlog
|
||||
FOR EACH ROW FOLLOWS trg_wacca_rank_update_remove
|
||||
INSERT INTO wacca_user_ranking_cache
|
||||
(user_id, achievement_sum, play_count, full_combo_count, all_perfect_count)
|
||||
VALUES (NEW.user_id, NEW.achievement, 1, NEW.is_full_combo, NEW.is_all_perfect)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
achievement_sum = achievement_sum + NEW.achievement,
|
||||
play_count = play_count + 1,
|
||||
full_combo_count = full_combo_count + NEW.is_full_combo,
|
||||
all_perfect_count = all_perfect_count + NEW.is_all_perfect;
|
||||
@@ -0,0 +1,4 @@
|
||||
-- V1000.7 left two foreign keys on user_card_id. The older restrictive key
|
||||
-- prevents the newer cascading relationship from deleting print details.
|
||||
ALTER TABLE maimai2_user_print_detail
|
||||
DROP FOREIGN KEY IF EXISTS FKDjNkXby95DMyQ9RKem;
|
||||
Reference in New Issue
Block a user