Repository navigation
Expand file tree
/
Copy pathmetapi_analysis.sql
More file actions
232 lines (221 loc) · 9.06 KB
/
Copy pathmetapi_analysis.sql
File metadata and controls
232 lines (221 loc) · 9.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
.mode column
.headers on
.separator " "
-- ============================================================
-- 1. 各站点总体延迟与成功率(最近24小时)
-- ============================================================
SELECT '=== 1. 站点延迟与成功率总览 ===' AS section;
SELECT
s.name AS site_name,
COUNT(*) AS total_calls,
SUM(CASE WHEN pl.status = 'success' THEN 1 ELSE 0 END) AS success_count,
SUM(CASE WHEN pl.status != 'success' THEN 1 ELSE 0 END) AS fail_count,
ROUND(100.0 * SUM(CASE WHEN pl.status = 'success' THEN 1 ELSE 0 END) / COUNT(*), 1) AS success_rate_pct,
ROUND(AVG(CASE WHEN pl.status = 'success' THEN pl.latency_ms END)) AS avg_latency_ms,
ROUND(MIN(CASE WHEN pl.status = 'success' THEN pl.latency_ms END)) AS min_latency_ms,
ROUND(MAX(CASE WHEN pl.status = 'success' THEN pl.latency_ms END)) AS max_latency_ms
FROM proxy_logs pl
JOIN route_channels rc ON pl.channel_id = rc.id
JOIN accounts a ON rc.account_id = a.id
JOIN sites s ON a.site_id = s.id
WHERE pl.created_at >= datetime('now', '-24 hours')
GROUP BY s.id, s.name
ORDER BY avg_latency_ms ASC;
-- ============================================================
-- 2. 各站点 P50/P90/P99 延迟分位数
-- ============================================================
SELECT '=== 2. 站点延迟分位数 ===' AS section;
WITH ranked AS (
SELECT
s.id AS site_id,
s.name AS site_name,
pl.latency_ms,
ROW_NUMBER() OVER (PARTITION BY s.id ORDER BY pl.latency_ms) AS rn,
COUNT(*) OVER (PARTITION BY s.id) AS cnt
FROM proxy_logs pl
JOIN route_channels rc ON pl.channel_id = rc.id
JOIN accounts a ON rc.account_id = a.id
JOIN sites s ON a.site_id = s.id
WHERE pl.status = 'success'
AND pl.created_at >= datetime('now', '-24 hours')
)
SELECT
site_name,
cnt AS samples,
MAX(CASE WHEN rn = CAST(cnt * 0.5 AS INTEGER) + 1 THEN latency_ms END) AS p50_ms,
MAX(CASE WHEN rn = CAST(cnt * 0.9 AS INTEGER) + 1 THEN latency_ms END) AS p90_ms,
MAX(CASE WHEN rn = CAST(cnt * 0.99 AS INTEGER) + 1 THEN latency_ms END) AS p99_ms
FROM ranked
GROUP BY site_id, site_name
HAVING cnt >= 3
ORDER BY p50_ms ASC;
-- ============================================================
-- 3. 模型×站点延迟矩阵(哪个模型在哪个站点最慢)
-- ============================================================
SELECT '=== 3. 模型×站点延迟矩阵 ===' AS section;
SELECT
s.name AS site_name,
pl.model_requested,
COUNT(*) AS calls,
ROUND(AVG(CASE WHEN pl.status = 'success' THEN pl.latency_ms END)) AS avg_latency_ms,
ROUND(100.0 * SUM(CASE WHEN pl.status = 'success' THEN 1 ELSE 0 END) / COUNT(*), 1) AS success_rate_pct
FROM proxy_logs pl
JOIN route_channels rc ON pl.channel_id = rc.id
JOIN accounts a ON rc.account_id = a.id
JOIN sites s ON a.site_id = s.id
WHERE pl.created_at >= datetime('now', '-24 hours')
GROUP BY s.id, s.name, pl.model_requested
HAVING calls >= 2
ORDER BY avg_latency_ms DESC
LIMIT 50;
-- ============================================================
-- 4. 各站点错误率排行
-- ============================================================
SELECT '=== 4. 站点错误率排行 ===' AS section;
SELECT
s.name AS site_name,
s.id AS site_id,
COUNT(*) AS total_calls,
SUM(CASE WHEN pl.status != 'success' THEN 1 ELSE 0 END) AS errors,
ROUND(100.0 * SUM(CASE WHEN pl.status != 'success' THEN 1 ELSE 0 END) / COUNT(*), 1) AS error_rate_pct,
GROUP_CONCAT(DISTINCT pl.http_status) AS error_http_statuses
FROM proxy_logs pl
JOIN route_channels rc ON pl.channel_id = rc.id
JOIN accounts a ON rc.account_id = a.id
JOIN sites s ON a.site_id = s.id
WHERE pl.created_at >= datetime('now', '-24 hours')
GROUP BY s.id, s.name
HAVING error_rate_pct > 0
ORDER BY error_rate_pct DESC;
-- ============================================================
-- 5. 错误类型分布
-- ============================================================
SELECT '=== 5. 错误类型分布 ===' AS section;
SELECT
s.name AS site_name,
pl.http_status,
CASE
WHEN pl.http_status >= 500 THEN '5xx_server'
WHEN pl.http_status = 429 THEN '429_ratelimit'
WHEN pl.http_status IN (401, 403) THEN 'auth_error'
WHEN pl.http_status >= 400 THEN '4xx_client'
ELSE 'other'
END AS error_category,
COUNT(*) AS count,
SUBSTR(pl.error_message, 1, 120) AS sample_error
FROM proxy_logs pl
JOIN route_channels rc ON pl.channel_id = rc.id
JOIN accounts a ON rc.account_id = a.id
JOIN sites s ON a.site_id = s.id
WHERE pl.status != 'success'
AND pl.created_at >= datetime('now', '-24 hours')
GROUP BY s.id, s.name, pl.http_status
ORDER BY count DESC
LIMIT 40;
-- ============================================================
-- 6. 连续失败渠道(需要关注的)
-- ============================================================
SELECT '=== 6. 连续失败渠道 ===' AS section;
SELECT
rc.id AS channel_id,
s.name AS site_name,
a.username,
rc.fail_count,
rc.success_count,
rc.consecutive_fail_count,
rc.cooldown_level,
rc.cooldown_until,
rc.last_fail_at,
ROUND(CAST(rc.total_latency_ms AS REAL) / NULLIF(rc.success_count, 0)) AS avg_latency_ms,
CASE WHEN rc.cooldown_until > datetime('now') THEN 'COOLING' ELSE 'ACTIVE' END AS state
FROM route_channels rc
JOIN accounts a ON rc.account_id = a.id
JOIN sites s ON a.site_id = s.id
WHERE rc.enabled = 1
AND rc.fail_count > 0
ORDER BY rc.consecutive_fail_count DESC, rc.fail_count DESC
LIMIT 30;
-- ============================================================
-- 7. 站点重试消耗
-- ============================================================
SELECT '=== 7. 站点重试消耗 ===' AS section;
SELECT
s.name AS site_name,
SUM(pl.retry_count) AS total_retries,
COUNT(*) AS total_requests,
ROUND(1.0 * SUM(pl.retry_count) / COUNT(*), 2) AS avg_retries_per_req,
SUM(CASE WHEN pl.retry_count > 0 THEN 1 ELSE 0 END) AS requests_with_retry
FROM proxy_logs pl
JOIN route_channels rc ON pl.channel_id = rc.id
JOIN accounts a ON rc.account_id = a.id
JOIN sites s ON a.site_id = s.id
WHERE pl.created_at >= datetime('now', '-24 hours')
GROUP BY s.id, s.name
HAVING total_retries > 0
ORDER BY total_retries DESC;
-- ============================================================
-- 8. 渠道状态总览(按站点聚合)
-- ============================================================
SELECT '=== 8. 渠道状态总览 ===' AS section;
SELECT
s.name AS site_name,
s.status AS site_status,
s.global_weight,
COUNT(rc.id) AS total_channels,
SUM(CASE WHEN rc.enabled = 1 THEN 1 ELSE 0 END) AS enabled_channels,
SUM(CASE WHEN rc.cooldown_until > datetime('now') THEN 1 ELSE 0 END) AS cooling_channels,
SUM(rc.success_count) AS total_success,
SUM(rc.fail_count) AS total_fail,
ROUND(100.0 * SUM(rc.success_count) / NULLIF(SUM(rc.success_count) + SUM(rc.fail_count), 0), 1) AS success_rate_pct,
ROUND(CAST(SUM(rc.total_latency_ms) AS REAL) / NULLIF(SUM(rc.success_count), 0)) AS avg_latency_ms
FROM sites s
LEFT JOIN accounts a ON s.id = a.site_id
LEFT JOIN route_channels rc ON a.id = rc.account_id
GROUP BY s.id, s.name, s.status, s.global_weight
ORDER BY success_rate_pct ASC;
-- ============================================================
-- 9. 运行时健康状态 JSON
-- ============================================================
SELECT '=== 9. 运行时健康状态 ===' AS section;
SELECT value FROM settings WHERE key = 'token_router_site_runtime_health_v1';
-- ============================================================
-- 10. 站点综合健康评分(低分=更差)
-- ============================================================
SELECT '=== 10. 站点综合健康评分 ===' AS section;
SELECT
s.name AS site_name,
s.global_weight,
COUNT(pl.id) AS total_calls,
ROUND(100.0 * SUM(CASE WHEN pl.status = 'success' THEN 1 ELSE 0 END) / COUNT(*), 1) AS success_rate,
ROUND(AVG(CASE WHEN pl.status = 'success' THEN pl.latency_ms END)) AS avg_latency,
SUM(pl.retry_count) AS total_retries,
ROUND(
(100.0 * SUM(CASE WHEN pl.status = 'success' THEN 1 ELSE 0 END) / COUNT(*))
* (1.0 / (1.0 + COALESCE(AVG(CASE WHEN pl.status = 'success' THEN pl.latency_ms END), 10000) / 1000.0))
* (1.0 / (1.0 + 1.0 * SUM(pl.retry_count) / COUNT(*))),
2
) AS health_score
FROM proxy_logs pl
JOIN route_channels rc ON pl.channel_id = rc.id
JOIN accounts a ON rc.account_id = a.id
JOIN sites s ON a.site_id = s.id
WHERE pl.created_at >= datetime('now', '-24 hours')
GROUP BY s.id, s.name, s.global_weight
ORDER BY health_score ASC;
-- ============================================================
-- 11. 每小时趋势(延迟+错误)
-- ============================================================
SELECT '=== 11. 每小时趋势 ===' AS section;
SELECT
s.name AS site_name,
strftime('%Y-%m-%d %H:00', pl.created_at) AS hour_bucket,
COUNT(*) AS calls,
ROUND(AVG(CASE WHEN pl.status = 'success' THEN pl.latency_ms END)) AS avg_latency_ms,
SUM(CASE WHEN pl.status != 'success' THEN 1 ELSE 0 END) AS errors
FROM proxy_logs pl
JOIN route_channels rc ON pl.channel_id = rc.id
JOIN accounts a ON rc.account_id = a.id
JOIN sites s ON a.site_id = s.id
WHERE pl.created_at >= datetime('now', '-24 hours')
GROUP BY s.id, s.name, hour_bucket
ORDER BY s.name, hour_bucket;