检查一个子查询中的所有行是否在另一子查询中具有所有行

时间:2018-09-12 15:03:25

标签: sql sql-server performance sql-server-2014

策略在insuranceTypes中有一组PolicyCoverage
对于insuranceTypes中的特定组织,策略具有一组PolicyPermissionInsuranceType

我正在尝试针对特定组织,用户和权限在PolicyCoverage中拥有所有类型的保险类型PolicyPermissionInsuranceType的保单。

在C#中,我将规则(为组织找到一个策略)评估为:

 public class ReadPolicyLimitedPermission
 {
        private IEnumerable<Guid> InsuranceTypeIds { get; }

        public bool Validate(Policy entity)
        {
            return !entity.InsuranceTypes.Except(InsuranceTypeIds).Any();
        }
 }

我正在尝试为数据库中的所有策略编写一个等于该规则的查询。我具有的查询如下所示,但是当提供userId且表中没有记录时,查询确实很慢。 所以问题是,有没有更好的方法来执行这种检查?

查询:

declare @UserId uniqueidentifier = newId() --Does not exist
declare @Permission nvarchar(150) = 'ReadPolicyLimitedPermission'

select p.Id
from test.Policy p
where
not exists
(
    select 
        pc.insuranceTypeId
    from
        test.PolicyCoverage pc
    where
        pc.PolicyId = p.Id

    except

    select
        ppit.InsuranceType 
    from
        test.PolicyPermissionInsuranceType ppit
    where
        ppit.UserId = @UserId and
        ppit.Permission = @Permission and
        ppit.OrganizationId = p.OrganizationId
)

表格大小:

Policy 201762 rows
PolicyCoverage 393004 rows
PolicyPermissionInsuranceType 36984 rows

执行计划: enter image description here

表结构:

CREATE TABLE [test].[Policy](
    [Id] [uniqueidentifier] NOT NULL,
    [OrganizationId] [uniqueidentifier] NOT NULL,
PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

CREATE TABLE [test].[PolicyCoverage](
    [PolicyId] [uniqueidentifier] NOT NULL,
    [InsuranceTypeId] [uniqueidentifier] NOT NULL
) ON [PRIMARY]

CREATE TABLE [test].[PolicyPermissionInsuranceType](
    [UserId] [uniqueidentifier] NOT NULL,
    [OrganizationId] [uniqueidentifier] NOT NULL,
    [Permission] [nvarchar](50) NOT NULL,
    [InsuranceType] [uniqueidentifier] NOT NULL,
 CONSTRAINT [PK_PolicyPermissionInsuranceType] PRIMARY KEY CLUSTERED 
(
    [UserId] ASC,
    [OrganizationId] ASC,
    [Permission] ASC,
    [InsuranceType] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

或者是否可以以其他方式为表PolicyPermissionInsuranceType

存储数据

示例:

Policy 1
  -Org 1 
    -Type 1
    -Type 2
Policy 2
  -Org 1
    -Type 1
    -Type 3


PolicyPermission 1
-Org1
-Type1
-Type2
-Type5

他们查询应该返回Policy1,因为它具有policyPermission表中的所有类型(Type1,Type2),但不能返回Policy2,因为它具有Type3,而Policy3没有。

2 个答案:

答案 0 :(得分:1)

如果尝试此操作怎么办:

select a.id from (
    select p.id,ppt.userid From test.Policy p
    join test.PolicyCoverage pc on pc.policyid = p.id
    left join test.PolicyPermissionInsuranceType ppt on ppt.InsuranceType = pc.insurancetypeid
      and ppt.OrganizationId = p.OrganizationId
      and ppt.UserId = @UserId 
      and ppt.Permission = @Permission 
)a
group by a.id
having  COUNT(a.id) = COUNT(a.userid)

答案 1 :(得分:0)

我将其发布为答案,因为我想添加一些可以测试的代码,因此似乎不适合注释。除非您觉得有用,否则会很乐意删除。

您可能希望预先在子查询中创建第二个表作为临时表,然后在子查询中引用该表,这可能会加快速度:

declare @UserId uniqueidentifier = newId() --Does not exist
declare @Permission nvarchar(150) = 'ReadPolicyLimitedPermission'

-- temp table here
select ppit.InsuranceType, ppit.OrganizationId 
into #temp
from test.PolicyPermissionInsuranceType ppit
where ppit.UserId = @UserId and
      ppit.Permission = @Permission

-- original modified query with temp table
select p.Id
from test.Policy p
where
not exists
(
    select pc.insuranceTypeId
    from test.PolicyCoverage pc
    where pc.PolicyId = p.Id

    except

    select ppit.InsuranceType 
    from #temp ppit        
    where ppit.OrganizationId = p.OrganizationId
)