2011-02-01 3 views
1

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

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) 
) 

Существует т о: м связь между документами и классами и документами и жетонами.

Я бы хотел (а) определить определенную статистику. Один stat - это 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? Если нет, то лучший способ? Я мог бы также изменить базовую структуру базы данных, чтобы потенциально ускорить работу ...

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

+0

Откуда берутся гребни? – RichardTheKiwi

+0

sql server 2005 – cs0815

+0

@cyberkiwi извините, забыл материал для расчески – cs0815

ответ

3

Прежде всего, даже если вы сделали это КТР, имейте в виду, что, поскольку у вас есть КТР (гребни) дважды в запросе , выполняется 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 

Это означает, что действительно нет никакого значения, добавляя КЛАССЫ к соединению, так как она будет завершена покрыта 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 бесполезно - они всегда уникальны.

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

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

С

  • КРОССА объединяет все классы (которые есть документы) на лексемы; и
  • В Перекрестных объединяют все маркера (которые имеют документы) к классам

Пересечение явно просто маркеры, которые существуют в документах INNER JOIN классов, которые существуют в документах, на тот же documentid, например,

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 
-1

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