SQL Server запрос на пересечение - PullRequest
1 голос
/ 01 февраля 2011

У меня есть база данных, определенная следующим образом:

create table Classes (
   Id INT not null,
   Text NVARCHAR(255) null,
   primary key (Id)
)

create table Documents (
   Id INT not null,
   Title NVARCHAR(MAX) null,
   Abstract NVARCHAR(MAX) null,
   Year INT null,
   primary key (Id)
)

create table Documents_Tokens (
   DocumentFk INT not null,
   TokenFk INT not null
)

create table Documents_Classes (
   DocumentFk INT not null,
   ClassFk INT not null
)

create table Tokens (
   Id INT not null,
   Text NVARCHAR(255) null,
   primary key (Id)
)

Между документами, классами, документами и токенами существует отношение m: m.

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

with combs as
(
    select 
        a.Id as classid, 
        a.text as class,
        b.Id as tokenid, 
        b.text as token
        from dbo.Classes as a
        cross join dbo.Tokens as b
)
,A as
(
    select token, class, count(distinct DocumentFk) as A from
    (
        select
            token,
            class,
            DocumentFk
        from combs
        inner join dbo.Documents_Classes on classid = ClassFk
        group by token, DocumentFk, class
            intersect
        select
            token,
            class,
            DocumentFk
        from combs
        inner join dbo.Documents_Tokens on tokenid = tokenFk
        group by token, DocumentFk, class
    ) T group by token, class
)
...

К сожалению, этот запрос занимает много времени (я добавил индексы после запуска анализатора запросов). Это самый эффективный способ определить A? Если нет, то есть ли лучший способ? Я также мог бы изменить базовую структуру базы данных, чтобы потенциально ускорить процесс ...

Любая обратная связь будет принята с благодарностью.

Ответы [ 2 ]

3 голосов
/ 01 февраля 2011

Прежде всего, даже если вы сделали его CTE, имейте в виду, что, поскольку у вас дважды в запросе CTE (расчески), выполняется CROSS JOIN TWICE !

Во-вторых, как только это станет ясно, вам нужно только перенести идентификаторы и в конце соединиться, чтобы получить текст.

Первая часть действительно

    select
        token,
        class,
        DocumentFk
    from (--> expanded = tokens cross join classes <--)
    inner join dbo.Documents_Classes on classid = ClassFk
    group by token, DocumentFk, class

Что означает,действительно нет никакого значения, добавляющего CLASSES к соединению, так как оно завершено при помощи Documents_Classes.Первая часть также может быть написана

    select
        token_id,
        class_id,
        DocumentFk
    from TOKENS
    CROSS join dbo.Documents_Classes
    --group by token_id, DocumentFk, class_id

Следующее, что следует отметить, это то, что CROSS JOIN по определению делает GROUP BY бесполезным - они всегда уникальны.

Вторая часть упрощает

    select
        token_id,
        class_id,
        DocumentFk
    from CLASSES
    CROSS join dbo.Documents_Tokens

Поскольку

  • КРЕСТ соединяет все классы (с документами) с токенами;и
  • B CROSS объединяет все токены (с документами) в классы

Пересечение - это просто просто токены, которые существуют в документах. INNER JOIN классы, которые существуют в документах одного документаНапример,

select C.text class, T.text token, count(DC.DocumentFk) as CountDocument
from Documents_Classes DC
inner join Documents_Tokens DT on DC.DocumentFk = DT.DocumentFk
inner join Classes C on DC.classFk = c.id
inner join Tokens T on DT.tokenFk = t.id
group by C.text, T.text, C.id, T.id
0 голосов
/ 01 февраля 2011

Перепишите его как одно внутреннее объединение, чтобы оптимизатор упростил жизнь

...