From a47502f07e4f233a536c7ff38849f2ee0adf4f85 Mon Sep 17 00:00:00 2001 From: milky0217 Date: Wed, 15 Jul 2026 10:52:24 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E5=90=88=E5=B9=B6=20insert=5Fweather?= =?UTF-8?q?=5Fdata=20N+1=20=E6=9F=A5=E8=AF=A2=E4=B8=BA=E5=8D=95=E6=AC=A1?= =?UTF-8?q?=EF=BC=9B=E6=B7=BB=E5=8A=A0=20Docker=20=E5=86=85=E5=AD=98?= =?UTF-8?q?=E9=99=90=E5=88=B6=E5=92=8C=E7=A3=81=E7=9B=98=E5=91=8A=E8=AD=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/db.rs | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/db.rs b/src/db.rs index 308789b..811f0bc 100644 --- a/src/db.rs +++ b/src/db.rs @@ -9,15 +9,36 @@ use crate::error::AppError; // 用于插入weather_data的数据 pub async fn insert_weather_data(pool: &PgPool, weather_data: &WeatherData, user_id: i32) -> Result { - // 配额检查:非付费用户数据条数限制 - let user = get_user_by_id(pool, user_id).await?; - let is_active_member = user.is_member && user.membership_expires_at.is_none_or(|expires| expires > Utc::now()); + // 单次查询获取用户会员状态和数据条数(原 N+1:get_user_by_id + count_user_weather_data → 合并为 1 次) + #[derive(FromRow)] + struct UserQuota { + is_member: bool, + paid_expires_at: Option>, + data_count: i64, + } + + let quota = sqlx::query_as::<_, UserQuota>( + r#" + SELECT + u.is_member, + u.paid_expires_at, + (SELECT COUNT(*) FROM weather_data w WHERE w.user_id = $1)::BIGINT AS data_count + FROM users u + WHERE u.id = $1 + "#, + ) + .bind(user_id) + .fetch_optional(pool) + .await + .map_err(|e| AppError::Database(format!("查询用户配额失败: {}", e)))? + .ok_or_else(|| AppError::NotFound("用户不存在".to_string()))?; + + let is_active_member = quota.is_member && quota.paid_expires_at.is_none_or(|expires| expires > Utc::now()); // 维护模式:非会员使用更高的临时限额,防止资源滥用 let is_maintenance = std::env::var("PAYMENT_MAINTENANCE_MODE").ok() == Some("true".to_string()); if !is_active_member { - let current_count = count_user_weather_data(pool, user_id).await?; let limit: i64 = if is_maintenance { env::var("MAINTENANCE_MODE_DATA_LIMIT") .unwrap_or_else(|_| "500".to_string()) @@ -30,7 +51,7 @@ pub async fn insert_weather_data(pool: &PgPool, weather_data: &WeatherData, user .unwrap_or(20) }; - if current_count >= limit { + if quota.data_count >= limit { return Err(AppError::Forbidden("数据条数已达上限,请升级为付费用户".to_string())); } }