SQL Server相交查询

时间:2011-02-01 09:04:44

标签: sql sql-server-2005 tsql query-optimization intersect

我的数据库定义如下:

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 个答案:

答案 0 :(得分:3)

首先,即使您已将其设为CTE,请记住,因为您在查询中有两次CTE(梳子),CROSS JOIN会执行 TWICE

第二个是,一旦变得清晰,你应该只转发ID并在最后加入以获得文本。

第一部分真的是

    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

由于

  • CROSS将所有类(有文档)加入令牌;和
  • 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

答案 1 :(得分:-1)

将其重写为单个内部联接,以使优化程序更轻松