Проверьте, все ли строки в одном подзапросе имеют все строки в другом подзапросе - PullRequest
0 голосов
/ 12 сентября 2018

У политики есть набор 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, которого у PolicyPermission1 нет.

Ответы [ 2 ]

0 голосов
/ 15 сентября 2018

что если вы попробуете это:

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)
0 голосов
/ 12 сентября 2018

Я публикую это как ответ, так как хотел добавить код, который можно было протестировать, поэтому он не подходил для комментариев.Удачно удалится, если вы не найдете это полезным.

Вы можете заранее создать вторую таблицу в своем подзапросе как временную таблицу, а затем ссылаться на нее в подзапросе, что может ускорить процесс:

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
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...