多租户统计必须显式包含tenant_id:WHERE中漏写导致跨租户汇总,GROUP BY中漏写导致租户数据合并,PARTITION BY和JOIN中漏写同样破坏隔离,tenant_id是统计口径的强制基石。

WHERE子句必须包含tenant_id过滤,否则统计结果错乱
多租户场景下,所有聚合查询若漏加tenant_id条件,会跨租户汇总数据,导致资源占用被严重高估。这不是逻辑错误,而是数据隔离失效的典型表现。
- 即使表结构含
tenant_id字段,也不代表查询自动按租户切分——SQL无“隐式租户上下文” - 应用层传入的
tenant_id必须显式出现在WHERE中,不能只靠JOIN关联表带出 - 使用视图或物化视图时,需确认其定义里已固化
tenant_id = ?,否则视图本身不安全
GROUP BY必须显式包含tenant_id,不可依赖索引或主键隐含
当需要“每个租户各自分组统计”时,tenant_id必须作为GROUP BY的第一项(或至少存在),否则数据库可能合并不同租户的同名分组(如两个租户都有service_a,会被合为一条)。
- 错误写法:
GROUP BY service_name→ 租户A和租户B的service_a计数相加 - 正确写法:
GROUP BY tenant_id, service_name - 若业务要求“先按租户、再按资源类型、再按日期”,则
GROUP BY tenant_id, resource_type, DATE(created_at),顺序影响结果可读性但不影响正确性
窗口函数中PARTITION BY tenant_id用于租户内排名或累计计算
当统计需求超出简单分组(例如“每个租户内CPU使用率Top 3的实例”),需用窗口函数,此时PARTITION BY是租户隔离的关键。
-
ROW_NUMBER() OVER (PARTITION BY tenant_id ORDER BY cpu_usage DESC)→ 每个租户独立编号 - 漏写
PARTITION BY tenant_id会导致全局排序,Top 3可能全属于一个租户 -
SUM(used_memory) OVER (PARTITION BY tenant_id)可算各租户内存总用量,避免重复JOIN聚合表
联表统计时,所有JOIN表都需对齐tenant_id,防止笛卡尔积或漏过滤
涉及资源表、配额表、账单表等多表关联时,仅主表加WHERE tenant_id = ?不够——若关联表未加租户条件或JOIN条件缺失tenant_id,可能引入其他租户数据或空匹配。
- 错误:主表
resources加了WHERE tenant_id = 't1',但JOIN quotas ON resources.service_id = quotas.service_id未限定quotas.tenant_id = 't1'→ 可能拉取到租户t2的配额 - 正确:所有JOIN条件中补上
AND quotas.tenant_id = resources.tenant_id,且quotas表WHERE也建议再过滤一次 - 使用LEFT JOIN时更危险:若右表无匹配且未限制
tenant_id,NULL行可能被误认为本租户“无配额”,实则是跨租户数据污染
租户维度不是可选标签,是统计口径的基石。哪怕临时查表验证,也要养成一眼扫WHERE和GROUP BY是否同时出现tenant_id的习惯——少一个,结果就不可信。










