SQL 服务器 - 使用交叉应用的行级安全性

SQL Server - Row Level security using Cross Apply

我正在为 SQL Server/Azure SQL 数据库中的行级安全性开发过滤器谓词。

与可见性硬币相关的应用程序逻辑要求必须阅读大量 tables 才能了解确定的用户是否可以阅读或更少阅读一行。我制定了以下逻辑:

代码如下:

   CREATE FUNCTION [scr].[prj_Projects](@ProjectId INT, @FilterId1 INT, @FilterId2 INT, @FilterId3 INT, @FilterId4 INT, @FilterId5 INT, @FilterId6 INT)  
   RETURNS TABLE  
WITH SCHEMABINDING  
AS  
   RETURN (  
        WITH UserProfiles AS (
            SELECT up.Id
            FROM dbo.users u
                INNER JOIN dbo.UsersProfiles up ON up.UserId = u.Id
                INNER JOIN dbo.Profiles p ON p.id = up.ProfileId
            WHERE SESSION_CONTEXT(N'UserId') = u.Id
        )
            SELECT Result = 1
             FROM UserProfiles up
                CROSS APPLY [scr].[prj_ProfilesFilter1](up.Id, @FilterId1) 
                CROSS APPLY [scr].[prj_ProfilesFilter2](up.Id, @FilterId2) 
                CROSS APPLY [scr].[prj_ProfilesFilter3](up.Id, @FilterId3) 
                CROSS APPLY [scr].[prj_ProfilesFilter4](up.Id, @FilterId4) 
                CROSS APPLY [scr].[prj_ProfilesFilter5](up.Id, @FilterId5) 
                CROSS APPLY [scr].[prj_ProfilesFilter6](up.Id, @FilterId6) 
      )
                                                  
GO

在查询一个ITVF之后(它们的结构都一样)。

CREATE OR ALTER FUNCTION [scr].[prj_ProfilesFilter1] (@UserProfileId INTEGER, @FilterId1 INTEGER)
    RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN (
    WITH UserProfile AS (
        SELECT DISTINCT upba.FilterId1
        FROM dbo.UsersProfilesFilters upba
        WHERE upba.UserProfileId = @UserProfileId 
    ), Datas AS (

        SELECT b.Id
        FROM dbo.Filters1 b
        INNER JOIN UserProfile c ON c.FilterId1 = b.Id

        UNION ALL

        SELECT b.Id
        FROM dbo.Filters1 b
        WHERE NOT EXISTS (SELECT 1 FROM UserProfile) 
          
        UNION ALL
        
        SELECT -1
        WHERE NOT EXISTS (SELECT 1 FROM UserProfile)

    ) SELECT Id
     FROM Datas d
     WHERE d.Id = ISNULL(@FilterId1 , -1)
    
)
GO

本来以为设计还可以,可惜表演很烂。与执行计划无关(例如,我只看到查找而没有扫描),但问题与查询执行的大量扫描计数和逻辑读取有关(非常非常高)。这很奇怪,因为每个交叉应用 returns 只有一行并且只有设置操作。

对于如何避免这种大量的逻辑读取,您有什么想法吗? 我认为这是与 RLS

相关的错误

更新: 这里是查询的执行计划:https://www.brentozar.com/pastetheplan/?id=r1mHXespO 正如我所说,问题与查询执行的逻辑读取数和扫描计数有关,因为执行计划似乎没问题。

好的,我想通了问题:必须转换 SESSION_CONTEXT 过程的结果,否则 SQL 服务器无法对查询的基数进行正确的假设。铸造SESSION_CONTEXT,性能变得非常好

WHERE CAST(SESSION_CONTEXT(N'UserMail') AS NVARCHAR(255) = u.Email