Commit 98b4f92e 98b4f92e3cf7d503e7e4635d9a9ab39aaa4bce58 by 沈秋雨

perf(etl): 优化批量更新与批处理大小

- 将默认批处理大小 BATCH_SIZE 从 1 增大到 1000 提高效率
- 添加 BACKFILL_BATCH_SIZE 环境变量支持,默认为 5000 用于补数据批量控制
- 使用 SQL 的 VALUES 语法替换 executemany 实现批量更新 yinyan_song_records 平台字段
- 修改 runner 中补数据查询改用 BACKFILL_BATCH_SIZE 以提升性能
- 更新相关单元测试以适配新的批量更新 SQL 语句和参数格式
1 parent d8728ac1
...@@ -43,4 +43,5 @@ PLATFORM_KUGOU = '2' ...@@ -43,4 +43,5 @@ PLATFORM_KUGOU = '2'
43 PLATFORM_NETEASE = '4' 43 PLATFORM_NETEASE = '4'
44 PLATFORMS = [PLATFORM_QQ, PLATFORM_KUGOU, PLATFORM_NETEASE] 44 PLATFORMS = [PLATFORM_QQ, PLATFORM_KUGOU, PLATFORM_NETEASE]
45 45
46 BATCH_SIZE = 1 46 BATCH_SIZE = 1000
47 BACKFILL_BATCH_SIZE = int(os.environ.get('BACKFILL_BATCH_SIZE', '5000'))
......
...@@ -3,7 +3,7 @@ import json ...@@ -3,7 +3,7 @@ import json
3 import logging 3 import logging
4 from tqdm import tqdm 4 from tqdm import tqdm
5 5
6 from .config import PLATFORM_QQ, PLATFORM_KUGOU, PLATFORM_NETEASE, BATCH_SIZE, OSS_CONFIG 6 from .config import PLATFORM_QQ, PLATFORM_KUGOU, PLATFORM_NETEASE, BATCH_SIZE, BACKFILL_BATCH_SIZE, OSS_CONFIG
7 from .connections import get_hk_songs_conn, get_source_conn, get_spider_conn, get_pg_conn, get_oss_bucket 7 from .connections import get_hk_songs_conn, get_source_conn, get_spider_conn, get_pg_conn, get_oss_bucket
8 from .reader import ( 8 from .reader import (
9 iter_hk_songs_batches, 9 iter_hk_songs_batches,
...@@ -548,7 +548,7 @@ def backfill_yinyan_record_platforms(max_batches: int | None = None) -> None: ...@@ -548,7 +548,7 @@ def backfill_yinyan_record_platforms(max_batches: int | None = None) -> None:
548 pbar = tqdm(desc='backfill-yinyan-platforms') 548 pbar = tqdm(desc='backfill-yinyan-platforms')
549 while max_batches is None or batch_index < max_batches: 549 while max_batches is None or batch_index < max_batches:
550 with pg_conn.cursor() as pg_cur: 550 with pg_conn.cursor() as pg_cur:
551 rows = fetch_yinyan_records_missing_platform(pg_cur, BATCH_SIZE) 551 rows = fetch_yinyan_records_missing_platform(pg_cur, BACKFILL_BATCH_SIZE)
552 if not rows: 552 if not rows:
553 break 553 break
554 554
......
...@@ -56,15 +56,20 @@ def fetch_yinyan_records_missing_platform(cur, limit: int) -> list[dict]: ...@@ -56,15 +56,20 @@ def fetch_yinyan_records_missing_platform(cur, limit: int) -> list[dict]:
56 def update_yinyan_record_platforms(cur, records: list[dict]) -> None: 56 def update_yinyan_record_platforms(cur, records: list[dict]) -> None:
57 if not records: 57 if not records:
58 return 58 return
59 cur.executemany( 59 values_sql = ', '.join(['(%s::bigint, %s::bigint, %s::varchar)'] * len(records))
60 """ 60 params = []
61 UPDATE yinyan_song_records 61 for r in records:
62 SET platform = %s 62 params.extend([r['song_id'], r['record_id'], r['platform']])
63 WHERE song_id = %s 63 cur.execute(
64 AND record_id = %s 64 f"""
65 AND platform IS NULL 65 UPDATE yinyan_song_records AS ysr
66 SET platform = v.platform
67 FROM (VALUES {values_sql}) AS v(song_id, record_id, platform)
68 WHERE ysr.song_id = v.song_id
69 AND ysr.record_id = v.record_id
70 AND ysr.platform IS NULL
66 """, 71 """,
67 [(r['platform'], r['song_id'], r['record_id']) for r in records], 72 tuple(params),
68 ) 73 )
69 74
70 75
......
...@@ -97,10 +97,12 @@ def test_update_yinyan_record_platforms_fills_only_null_platform_rows(): ...@@ -97,10 +97,12 @@ def test_update_yinyan_record_platforms_fills_only_null_platform_rows():
97 {'song_id': 11, 'record_id': 101, 'platform': '2'}, 97 {'song_id': 11, 'record_id': 101, 'platform': '2'},
98 ]) 98 ])
99 99
100 sql, rows = cur.executemany.call_args[0] 100 sql, params = cur.execute.call_args[0]
101 assert 'SET platform = %s' in sql 101 assert 'UPDATE yinyan_song_records AS ysr' in sql
102 assert 'AND platform IS NULL' in sql 102 assert 'FROM (VALUES (%s::bigint, %s::bigint, %s::varchar), (%s::bigint, %s::bigint, %s::varchar))' in sql
103 assert rows == [('1', 10, 100), ('2', 11, 101)] 103 assert 'SET platform = v.platform' in sql
104 assert 'AND ysr.platform IS NULL' in sql
105 assert params == (10, 100, '1', 11, 101, '2')
104 106
105 107
106 def test_upsert_netease_songs_writes_album_json_column(): 108 def test_upsert_netease_songs_writes_album_json_column():
......