mysql 8.0 原生不支持行级安全策略(rls),所谓“rls延迟”实为视图、会话变量、缺失索引或审计插件等伪rls机制引发的性能问题,需通过explain、索引覆盖和关闭干扰组件定位根因。

MySQL 8.0 中没有「行级安全策略(Row-Level Security Policy)」这个原生功能。这是常见误解——很多人把 MySQL 的 ROW_FORMAT=COMPRESSED、SELECT ... FOR UPDATE、视图权限、或第三方中间件(如 ProxySQL 规则)误称为 RLS;也有人混淆了 PostgreSQL 的 RULE 或 RLS(CREATE POLICY)机制。
所以,第一件事得先确认:你遇到的“执行延迟”,真由 MySQL 自身的行级控制逻辑引发?还是被其他东西伪装成了它?
怎么判断是不是「伪 RLS 延迟」?
MySQL 8.0 原生不支持基于行的动态访问控制(即根据用户身份自动过滤行),它只提供:
- 表/列级权限(
GRANT SELECT(col1,col2) ON db.tbl) - 视图(可封装
WHERE user() = 'xxx'类逻辑,但性能差、不可下推) -
DEFINER存储过程(调用时以定义者权限执行,不等于行级过滤)
如果你在慢查询日志里看到类似这样的语句耗时突增:
SELECT * FROM orders WHERE user_id = CURRENT_USER();
那延迟大概率来自:
- 缺少
user_id索引,导致全表扫描 -
CURRENT_USER()是非确定性函数,无法走索引(除非你建了函数索引并显式引用) - 视图里嵌套了多层子查询 +
WHERE过滤,优化器放弃下推
排查要点:
- 查看
EXPLAIN FORMAT=TREE输出,确认是否走了索引、是否出现Using where; Using filesort - 检查该语句是否被缓存在查询缓存中(
MySQL 8.0已移除查询缓存,但应用层可能有自建缓存逻辑干扰判断) - 对比相同 SQL 在不同用户连接下执行时间:如果差异巨大,说明不是 SQL 本身问题,而是连接上下文(比如触发了不同执行计划、或客户端加了额外拦截逻辑)
如果你真用了视图模拟 RLS,为什么它会变慢?
很多团队用视图强行实现“多租户隔离”,例如:
CREATE VIEW tenant_orders AS SELECT * FROM orders WHERE tenant_id = @current_tenant;
这种写法在 MySQL 8.0 下极易踩坑:
-
@current_tenant是会话变量,MySQL 不会在优化阶段将其视为常量,导致无法使用tenant_id索引 - 视图无物化能力,每次查询都重跑全表扫描 + 过滤
- 若视图被嵌套在 JOIN 或子查询中,优化器可能完全放弃索引选择
改进方式:
- 改用显式参数化查询:
SELECT * FROM orders WHERE tenant_id = ?,确保传入的是字面量或绑定参数 - 在应用层拼接
WHERE tenant_id = ?,别依赖视图隐藏逻辑 - 如果必须用视图,配合
ALGORITHM=TEMPTABLE并确保tenant_id有索引,但性能仍不如直查
容易被忽略的「类 RLS」干扰源
有些延迟看似来自“行过滤”,实则是其他机制在背后拖慢:
-
UNION ALL多租户表路由:把不同租户数据分到不同物理表,再用视图UNION,一旦某张子表没索引或统计信息过期,整个UNION执行计划崩坏 - 触发器(
BEFORE SELECT不存在,但有人误以为能做行过滤):MySQL 不支持SELECT触发器,试图绕过只能靠代理或应用层,而代理层加规则会引入网络和解析开销 - 审计插件(如
audit_log或商业版Enterprise Firewall):开启细粒度 SQL 拦截后,每条语句都要匹配规则链,高并发下 CPU 成瓶颈
验证方法:
- 关闭审计插件:
SET GLOBAL audit_log_policy = NONE;,观察延迟是否消失 - 查
performance_schema.events_statements_summary_by_digest,看相同语句的AVERAGE_TIMER_WAIT是否随并发上升而线性增长(典型 CPU 绑定特征)
真正影响执行延迟的,从来不是“策略是否存在”,而是“策略如何落地”。MySQL 8.0 不提供开箱即用的 RLS,所有模拟方案都会带来额外解析、过滤或调度成本。与其纠结名字,不如盯住三样东西:执行计划是否稳定、索引是否覆盖过滤字段、是否有非必要中间层介入。











