From 07b016bff9efd1e1ecb2036942c05be0ee187921 Mon Sep 17 00:00:00 2001 From: vrubel Date: Sat, 20 Jun 2026 09:06:11 +0000 Subject: [PATCH] perf: SQL LIKE query instead of Python loop; skip warmup if cache >1000 --- bots/tracker.py | 65 ++++++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/bots/tracker.py b/bots/tracker.py index 75957b4..fbaaf8e 100644 --- a/bots/tracker.py +++ b/bots/tracker.py @@ -525,35 +525,34 @@ def scan_for_player(fide_id: int, max_tnr: int = None, results = [] seen_tnrs = set() - # Phase 1: check tnr_cache (instant SQL, no HTTP). Return immediately if found. - for cluster_lo, cluster_hi in [(1434000, 1450000)]: - conn = _get_conn() - cached_tnrs = [ - r[0] for r in conn.execute( - 'SELECT tnr FROM tnr_cache WHERE tnr >= ? AND tnr <= ? ORDER BY tnr DESC', - (cluster_lo, cluster_hi)).fetchall() - ] - conn.close() - for tnr in cached_tnrs: - cdata = _get_cached_tnr(tnr) - if cdata is None: - continue - player_info = cdata['players'].get(fide_id) - if player_info is None: - continue - results.append({ - 'tnr': tnr, - 'url': f'https://chess-results.com/tnr{tnr}.aspx?lan=11', - 'name': cdata['name'] or f'Tournament {tnr}', - 'start_date': cdata['start_date'], - 'end_date': cdata['end_date'], - 'sno': player_info['sno'], - 'player_name': player_info['name'], - 'fide_id': fide_id, - }) - if results: - set_tnr_state('max_tnr_seen', str(max(r['tnr'] for r in results))) - return results + # Phase 1: check tnr_cache via SQL (single query, instant). Return if found. + conn = _get_conn() + pattern = f'%"{fide_id}"%' + rows = conn.execute( + 'SELECT tnr, name, start_date, end_date, players_json FROM tnr_cache ' + 'WHERE tnr >= ? AND tnr <= ? AND players_json LIKE ? ' + 'ORDER BY tnr DESC', + (1434000, 1450000, pattern)).fetchall() + conn.close() + for row in rows: + tnr, tname, tstart, tend, players_json = row + players = {int(k): v for k, v in json.loads(players_json).items()} + player_info = players.get(fide_id) + if player_info is None: + continue + results.append({ + 'tnr': tnr, + 'url': f'https://chess-results.com/tnr{tnr}.aspx?lan=11', + 'name': tname or f'Tournament {tnr}', + 'start_date': tstart, + 'end_date': tend, + 'sno': player_info['sno'], + 'player_name': player_info['name'], + 'fide_id': fide_id, + }) + if results: + set_tnr_state('max_tnr_seen', str(max(r['tnr'] for r in results))) + return results # Phase 2: cache miss — fall back to sequential TNR scan saved = int(get_tnr_state('max_tnr_seen', '0')) @@ -634,10 +633,16 @@ async def warmup_cache(context): """Build full tnr_cache index (runs once at startup, then every 6h).""" import asyncio, sys, traceback - # Skip if warmup already completed + # Skip if warmup already completed or cache already populated status = get_tnr_state('warmup_tnr', '') if status == 'done': return + conn = _get_conn() + cache_count = conn.execute('SELECT COUNT(*) FROM tnr_cache').fetchone()[0] + conn.close() + if cache_count > 1000: + set_tnr_state('warmup_tnr', 'done') + return print('warmup_cache: starting cluster scan (step=1, 1445000→1434000)...', file=sys.stderr) try: