如何优化SQL Server存储过程:基于参数过滤含加密行的数据
优化方案:单次查询实现需求
可以不用两次查询,也能结合CASE实现需求,下面提供两种高效的实现方案:
方案一:利用窗口函数(推荐,单次表扫描)
通过窗口函数在一次查询中全局判断是否存在加密行,再根据这个结果过滤数据:
CREATE PROCEDURE GetMyTableData @AllowedUser INT AS BEGIN SET NOCOUNT ON; SELECT * FROM ( SELECT *, -- 全局标记是否存在加密行(1=存在,0=不存在) MAX(CASE WHEN Encryption = 1 THEN 1 ELSE 0 END) OVER() AS HasEncryptedRows FROM MYTABLE ) t WHERE -- 无加密行时返回全部数据 HasEncryptedRows = 0 OR -- 有加密行时:返回未加密行 + 符合@AllowedUser的加密行 (Encryption = 0 OR (Encryption = 1 AND AllowedUser = @AllowedUser)); END
逻辑说明
MAX(CASE WHEN Encryption = 1 THEN 1 ELSE 0 END) OVER()会给每行数据添加一个全局标记:只要表中存在Encryption=1的行,标记值就是1,否则为0。- WHERE子句根据标记分支:无加密行时直接返回所有数据;有加密行时,放行所有未加密行,同时只保留符合用户权限的加密行。
方案二:利用EXISTS子查询
这种写法更简洁,SQL Server查询优化器通常会将其优化为单次表扫描:
CREATE PROCEDURE GetMyTableData @AllowedUser INT AS BEGIN SET NOCOUNT ON; SELECT * FROM MYTABLE WHERE -- 无加密行时返回全部数据 NOT EXISTS (SELECT 1 FROM MYTABLE WHERE Encryption = 1) OR -- 有加密行时的过滤规则 (Encryption = 0 OR (Encryption = 1 AND AllowedUser = @AllowedUser)); END
关于CASE语句的使用
单独的CASE是行级逻辑,无法直接实现全局是否存在加密行的判断,但可以结合窗口函数或聚合函数来完成,方案一中已经用到了CASE配合窗口函数的写法,实现了全局状态的标记。
内容的提问来源于stack exchange,提问作者Mirza Bilal
相关产品推荐
相关产品推荐

