Skip to content

Commit 5515d41

Browse files
committed
CHANGES:
- usage added to mv_statistics - several performance improvements on statistics queries (e.g. REST API) BUGFIX: - kills_ships missing from mv_statistics
1 parent 9a49f9b commit 5515d41

File tree

10 files changed

+74
-45
lines changed

10 files changed

+74
-45
lines changed

plugins/creditsystem/listener.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,10 @@ async def get_flighttime(self, ucid: str, campaign_id: int) -> int:
114114
async with self.apool.connection() as conn:
115115
cursor = await conn.execute("""
116116
SELECT COALESCE(ROUND(SUM(EXTRACT(EPOCH FROM (s.hop_off - s.hop_on)))), 0) AS playtime
117-
FROM statistics s, missions m, campaigns c, campaigns_servers cs
118-
WHERE s.player_ucid = %s AND c.id = %s AND s.mission_id = m.id AND cs.campaign_id = c.id
117+
FROM statistics s JOIN missions m ON m.id = s.mission_id
118+
JOIN campaigns c ON c.id = %s
119+
JOIN campaigns_servers cs ON cs.campaign_id = c.id
120+
WHERE s.player_ucid = %s
119121
AND m.server_name = cs.server_name
120122
AND tsrange(s.hop_on, s.hop_off) && tsrange(c.start, c.stop)
121123
""", (ucid, campaign_id))

plugins/missionstats/commands.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ async def player_modules_autocomplete(interaction: discord.Interaction, current:
2323
async def get_modules(ucid: str) -> list[str]:
2424
async with interaction.client.apool.connection() as conn:
2525
return [row[0] async for row in await conn.execute("""
26-
SELECT DISTINCT slot, COUNT(*) FROM statistics
26+
SELECT DISTINCT slot, usage FROM mv_statistics
2727
WHERE player_ucid = %s
2828
AND slot NOT IN ('', '?', '''forward_observer', 'instructor', 'observer', 'artillery_commander')
29-
GROUP BY 1 ORDER BY 2 DESC
29+
ORDER BY 2 DESC
3030
""", (ucid, ))]
3131

3232
try:

plugins/punishment/listener.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,8 @@ async def onMissionLoadEnd(self, server: Server, _: dict) -> None:
6060

6161
async def _get_flight_hours(self, player: Player) -> int:
6262
async with self.apool.connection() as conn:
63-
cursor = await conn.execute("""
64-
SELECT COALESCE(ROUND(SUM(EXTRACT(EPOCH FROM (COALESCE(hop_off, now() AT TIME ZONE 'utc') - hop_on)))) / 3600, 0)
65-
AS playtime
66-
FROM statistics WHERE player_ucid = %s
67-
""", (player.ucid, ))
63+
cursor = await conn.execute("SELECT SUM(playtime) FROM mv_statistics WHERE player_ucid = %s",
64+
(player.ucid, ))
6865
return (await cursor.fetchone())[0] if cursor.rowcount > 0 else 0
6966

7067
async def _get_punishment_points(self, player: Player) -> int:

plugins/restapi/commands.py

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import asyncio
22
import os
3-
43
import psycopg
54
import random
65
import re
@@ -283,7 +282,7 @@ async def serverstats(self, server_name: str = Query(default=None)):
283282
where = ""
284283
await cursor.execute(f"""
285284
SELECT SUM("totalPlayers") AS "totalPlayers", SUM("totalPlaytime") AS "totalPlaytime",
286-
SUM("avgPlaytime") AS "avgPlaytime", SUM("activePlayers") AS "activePlayers",
285+
SUM("avgPlaytime") AS "avgPlaytime",
287286
SUM("totalSorties") AS "totalSorties", SUM("totalKills") AS "totalKills",
288287
SUM("totalDeaths") AS "totalDeaths", SUM("totalPvPKills") AS "totalPvPKills",
289288
SUM("totalPvPDeaths") AS "totalPvPDeaths"
@@ -292,6 +291,15 @@ async def serverstats(self, server_name: str = Query(default=None)):
292291
""", {"server_name": server_name})
293292
serverstats = await cursor.fetchone()
294293

294+
if server_name:
295+
server = self.bot.servers.get(server_name)
296+
serverstats['activePlayers'] = len(server.get_active_players())
297+
else:
298+
active = 0
299+
for server in self.bot.servers.values():
300+
active += len(server.get_active_players())
301+
serverstats['activePlayers'] = active
302+
295303
if server_name:
296304
join = f"JOIN missions m ON s.mission_id = m.id AND m.server_name = %(server_name)s"
297305
else:
@@ -439,9 +447,9 @@ async def leaderboard(self, what: str, order: Literal['asc', 'desc'] = 'desc', q
439447
raise HTTPException(status_code=400, detail="Invalid ordering column supplied")
440448

441449
if server_name:
442-
join = "JOIN missions m ON s.mission_id = m.id AND m.server_name = %(server_name)s"
450+
where = "WHERE s.server_name = %(server_name)s"
443451
else:
444-
join = ""
452+
where = ""
445453

446454
async with self.apool.connection() as conn:
447455
async with conn.cursor(row_factory=dict_row) as cursor:
@@ -458,14 +466,14 @@ async def leaderboard(self, what: str, order: Literal['asc', 'desc'] = 'desc', q
458466
CASE WHEN SUM(s.deaths_pvp) = 0
459467
THEN SUM(s.pvp) ELSE ROUND(SUM(s.pvp::DECIMAL) / SUM(s.deaths_pvp::DECIMAL), 2)
460468
END AS "kdr_pvp",
461-
ROUND(SUM(EXTRACT(EPOCH FROM(COALESCE(s.hop_off, NOW() AT TIME ZONE 'UTC') - s.hop_on))))::BIGINT AS playtime,
469+
SUM(playtime)::BIGINT AS playtime,
462470
MAX(COALESCE(c.points, 0)) AS "credits",
463-
COUNT(*) OVER() as total_count
464-
FROM statistics s
471+
COUNT(s.usage) as total_count
472+
FROM mv_statistics s
465473
JOIN players p ON s.player_ucid = p.ucid
466-
{join}
467474
LEFT OUTER JOIN credits c ON c.player_ucid = s.player_ucid
468475
LEFT OUTER JOIN campaigns ca ON ca.id = c.campaign_id AND NOW() AT TIME ZONE 'utc' BETWEEN ca.start AND COALESCE(ca.stop, NOW() AT TIME ZONE 'utc')
476+
{where}
469477
GROUP BY 1, 2
470478
ORDER BY {order_column} {order}
471479
LIMIT %(limit)s
@@ -507,18 +515,17 @@ async def trueskill(self, limit: int = Query(default=10), offset: int = Query(de
507515
server_name: str = Query(default=None)):
508516
self.log.debug(f'Calling /trueskill with limit={limit}, server_name={server_name}')
509517
if server_name:
510-
join = "JOIN missions m ON s.mission_id = m.id AND m.server_name = %(server_name)s"
518+
where = "WHERE s.server_name = %(server_name)s"
511519
else:
512-
join = ""
520+
where = ""
513521
async with self.apool.connection() as conn:
514522
async with conn.cursor(row_factory=dict_row) as cursor:
515523
await cursor.execute(f"""
516524
SELECT p.name AS "nick", DATE_TRUNC('second', p.last_seen) AS "date",
517525
SUM(pvp) AS "kills_pvp", SUM(deaths_pvp) AS "deaths_pvp", t.skill_mu AS "TrueSkill"
518-
FROM statistics s JOIN players p ON s.player_ucid = p.ucid
526+
FROM mv_statistics s JOIN players p ON s.player_ucid = p.ucid
519527
JOIN trueskill t ON t.player_ucid = p.ucid
520-
{join}
521-
WHERE s.hop_on > (now() AT TIME ZONE 'utc') - interval '1 month'
528+
{where}
522529
GROUP BY 1, 2, 5 ORDER BY 5 DESC
523530
LIMIT {limit} OFFSET {offset}
524531
""", {"server_name": server_name})
@@ -633,11 +640,11 @@ async def stats(self, nick: str = Form(...), date: str | None = Form(None),
633640

634641
ucid = await self.get_ucid(nick, date)
635642
if server_name:
636-
join = "JOIN missions m ON s.mission_id = m.id AND m.server_name = %(server_name)s"
643+
where = "AND s.server_name = %(server_name)s"
637644
else:
638-
join = ""
645+
where = ""
639646
query = f"""
640-
SELECT COALESCE(ROUND(SUM(EXTRACT(EPOCH FROM(COALESCE(s.hop_off, NOW() AT TIME ZONE 'UTC') - s.hop_on)))), 0)::BIGINT AS playtime,
647+
SELECT COALESCE(SUM(playtime), 0)::BIGINT AS playtime,
641648
COALESCE(SUM(s.kills), 0) as "kills",
642649
COALESCE(SUM(s.deaths_planes + s.deaths_helicopters + s.deaths_ships + s.deaths_sams + s.deaths_ground), 0) AS "deaths",
643650
COALESCE(SUM(s.pvp), 0) AS "kills_pvp",
@@ -657,9 +664,9 @@ async def stats(self, nick: str = Form(...), date: str | None = Form(None),
657664
COALESCE(SUM(s.ejections), 0) AS "ejections",
658665
COALESCE(SUM(s.crashes), 0) AS "crashes",
659666
COALESCE(SUM(s.teamkills), 0) AS "teamkills"
660-
FROM statistics s
661-
{join}
667+
FROM mv_statistics s
662668
WHERE s.player_ucid = %(ucid)s
669+
{where}
663670
"""
664671
if last_session:
665672
if server_name:
@@ -685,19 +692,19 @@ async def stats(self, nick: str = Form(...), date: str | None = Form(None),
685692

686693
await cursor.execute("""
687694
SELECT slot AS "module", SUM(kills) AS "kills"
688-
FROM statistics
695+
FROM mv_statistics
689696
WHERE player_ucid = %s
690697
GROUP BY 1
691698
HAVING SUM(kills) > 1
692699
ORDER BY 2 DESC
693700
""", (ucid,))
694701
data['killsByModule'] = await cursor.fetchall()
695702
await cursor.execute("""
696-
SELECT slot AS "module",
703+
SELECT slot AS "module",
697704
CASE
698705
WHEN SUM(deaths) = 0 THEN SUM(kills)
699706
ELSE ROUND(SUM(kills) / SUM(deaths::DECIMAL), 2) END AS "kdr"
700-
FROM statistics
707+
FROM mv_statistics
701708
WHERE player_ucid = %s
702709
GROUP BY 1
703710
HAVING SUM(kills) > 1
@@ -713,18 +720,18 @@ async def modulestats(self, nick: str = Form(...), date: str | None = Form(None)
713720

714721
ucid = await self.get_ucid(nick, date)
715722
if server_name:
716-
join = "JOIN missions m ON s.mission_id = m.id AND m.server_name = %(server_name)s"
723+
where = "AND s.server_name = %(server_name)s"
717724
else:
718-
join = ""
725+
where = ""
719726
query = f"""
720727
SELECT s.slot AS "module",
721728
SUM(s.kills) AS "kills",
722729
SUM(s.deaths_planes + s.deaths_helicopters + s.deaths_ships + s.deaths_sams + s.deaths_ground) AS "deaths",
723730
CASE WHEN SUM(s.deaths_planes + s.deaths_helicopters + s.deaths_ships + s.deaths_sams + s.deaths_ground) = 0
724731
THEN SUM(s.kills) ELSE SUM(s.kills)::DECIMAL / SUM((s.deaths_planes + s.deaths_helicopters + s.deaths_ships + s.deaths_sams + s.deaths_ground)::DECIMAL) END AS "kdr"
725-
FROM statistics s
726-
{join}
732+
FROM mv_statistics s
727733
WHERE player_ucid = %(ucid)s
734+
{where}
728735
GROUP BY 1 HAVING SUM(kills) > 1
729736
ORDER BY 2 DESC
730737
"""

plugins/restapi/db/tables.sql

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
CREATE MATERIALIZED VIEW mv_serverstats AS
2-
SELECT m.server_name, COUNT(DISTINCT p.ucid) AS "totalPlayers",
3-
ROUND(SUM(EXTRACT(EPOCH FROM(COALESCE(s.hop_off, NOW() AT TIME ZONE 'UTC') - s.hop_on))) / 3600)::INTEGER AS "totalPlaytime",
4-
ROUND(AVG(EXTRACT(EPOCH FROM(COALESCE(s.hop_off, NOW() AT TIME ZONE 'UTC') - s.hop_on))))::INTEGER AS "avgPlaytime",
5-
SUM(CASE WHEN s.hop_off IS NULL THEN 1 ELSE 0 END) AS "activePlayers",
6-
COUNT(*) AS "totalSorties",
2+
SELECT s.server_name, COUNT(DISTINCT p.ucid) AS "totalPlayers",
3+
(SUM(s.playtime) / 3600)::INTEGER AS "totalPlaytime",
4+
(SUM(s.playtime) / SUM(s.usage))::INTEGER AS "avgPlaytime",
5+
SUM(s.usage) AS "totalSorties",
76
SUM(s.kills) AS "totalKills",
87
SUM(s.deaths) AS "totalDeaths",
98
SUM(s.pvp) AS "totalPvPKills",
109
SUM(s.deaths_pvp) AS "totalPvPDeaths",
1110
NOW() AT TIME ZONE 'UTC' as "timestamp"
1211
FROM players p
13-
JOIN statistics s ON p.ucid = s.player_ucid
14-
JOIN missions m on s.mission_id = m.id
12+
JOIN mv_statistics s ON p.ucid = s.player_ucid
1513
GROUP BY 1;

plugins/restapi/db/update_v1.2.sql

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
DROP MATERIALIZED VIEW IF EXISTS mv_serverstats;
2+
CREATE MATERIALIZED VIEW mv_serverstats AS
3+
SELECT s.server_name, COUNT(DISTINCT p.ucid) AS "totalPlayers",
4+
(SUM(s.playtime) / 3600)::INTEGER AS "totalPlaytime",
5+
(SUM(s.playtime) / SUM(s.usage))::INTEGER AS "avgPlaytime",
6+
SUM(s.usage) AS "totalSorties",
7+
SUM(s.kills) AS "totalKills",
8+
SUM(s.deaths) AS "totalDeaths",
9+
SUM(s.pvp) AS "totalPvPKills",
10+
SUM(s.deaths_pvp) AS "totalPvPDeaths",
11+
NOW() AT TIME ZONE 'UTC' as "timestamp"
12+
FROM players p
13+
JOIN mv_statistics s ON p.ucid = s.player_ucid
14+
GROUP BY 1;

plugins/restapi/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "1.2"
1+
__version__ = "1.3"

plugins/userstats/db/tables.sql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ CREATE TABLE IF NOT EXISTS squadron_members (squadron_id INTEGER NOT NULL, playe
66
CREATE UNIQUE INDEX IF NOT EXISTS idx_squadron_members ON squadron_members (player_ucid);
77
CREATE MATERIALIZED VIEW IF NOT EXISTS mv_statistics AS
88
SELECT s.player_ucid, m.server_name, s.slot, s.tail_no, s.side,
9-
SUM(s.kills) AS kills, SUM(s.pvp) AS pvp, SUM(s.deaths) AS deaths, SUM(s.ejections) AS ejections, SUM(s.crashes) AS crashes, SUM(s.teamkills) AS teamkills, SUM(s.takeoffs) AS takeoffs, SUM(s.landings) AS landings,
10-
SUM(s.kills_planes) AS kills_planes, SUM(s.kills_helicopters) AS kills_helicopters, SUM(s.kills_sams) AS kills_sams, SUM(s.kills_ground) AS kills_ground,
9+
COUNT(s.slot) AS usage, SUM(s.kills) AS kills, SUM(s.pvp) AS pvp, SUM(s.deaths) AS deaths, SUM(s.ejections) AS ejections, SUM(s.crashes) AS crashes, SUM(s.teamkills) AS teamkills, SUM(s.takeoffs) AS takeoffs, SUM(s.landings) AS landings,
10+
SUM(s.kills_planes) AS kills_planes, SUM(s.kills_helicopters) AS kills_helicopters, SUM(s.kills_ships) AS kills_ships, SUM(s.kills_sams) AS kills_sams, SUM(s.kills_ground) AS kills_ground,
1111
SUM(s.deaths_pvp) AS deaths_pvp, SUM(s.deaths_planes) AS deaths_planes, SUM(s.deaths_helicopters) AS deaths_helicopters, SUM(s.deaths_ships) AS deaths_ships, SUM(s.deaths_sams) AS deaths_sams, SUM(s.deaths_ground) AS deaths_ground,
1212
ROUND(SUM(EXTRACT(EPOCH FROM(COALESCE(s.hop_off, NOW() AT TIME ZONE 'UTC') - s.hop_on)))) AS playtime
1313
FROM statistics s JOIN missions m ON s.mission_id = m.id
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
DROP MATERIALIZED VIEW IF EXISTS mv_statistics;
2+
CREATE MATERIALIZED VIEW mv_statistics AS
3+
SELECT s.player_ucid, m.server_name, s.slot, s.tail_no, s.side,
4+
COUNT(s.slot) AS usage, SUM(s.kills) AS kills, SUM(s.pvp) AS pvp, SUM(s.deaths) AS deaths, SUM(s.ejections) AS ejections, SUM(s.crashes) AS crashes, SUM(s.teamkills) AS teamkills, SUM(s.takeoffs) AS takeoffs, SUM(s.landings) AS landings,
5+
SUM(s.kills_planes) AS kills_planes, SUM(s.kills_helicopters) AS kills_helicopters, SUM(s.kills_ships) AS kills_ships, SUM(s.kills_sams) AS kills_sams, SUM(s.kills_ground) AS kills_ground,
6+
SUM(s.deaths_pvp) AS deaths_pvp, SUM(s.deaths_planes) AS deaths_planes, SUM(s.deaths_helicopters) AS deaths_helicopters, SUM(s.deaths_ships) AS deaths_ships, SUM(s.deaths_sams) AS deaths_sams, SUM(s.deaths_ground) AS deaths_ground,
7+
ROUND(SUM(EXTRACT(EPOCH FROM(COALESCE(s.hop_off, NOW() AT TIME ZONE 'UTC') - s.hop_on)))) AS playtime
8+
FROM statistics s JOIN missions m ON s.mission_id = m.id
9+
GROUP BY 1, 2, 3, 4, 5;
10+
CREATE INDEX IF NOT EXISTS idx_mv_statistics_ucid ON mv_statistics (player_ucid);
11+
CREATE INDEX IF NOT EXISTS idx_mv_statistics_tail_no ON mv_statistics (tail_no);

plugins/userstats/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "3.10"
1+
__version__ = "3.11"

0 commit comments

Comments
 (0)