0

问题查询使用多个 Intersect。

通过 count() = 6 将其更改为 in ('alpha','beta','gamma','delta','epsilon','phi') 组不是一个选项,因为应用程序支持通配符(例如 alpha%)。但是 count() = 6 查询运行时间不到 1 秒。

使用通配符可以使用多个连接,这就是它过去的结构。在 4 或更少时,Intersect 的性能优于多个连接,但不幸的是没有在 5 或更多时进行测试。

查询在任何 4 个术语上都表现出色 - 不到 1 秒。
从字面上看,任何 4 - 前 4、最后 4 或中间 4。
在 5 或更多然后它死了 - 我在 2 分钟时终止了查询。
让它运行 6 个术语 - 5 分钟返回 795 行。

查询计划将循环与合并连接最多混合使用 4 个术语。
在 5 个或更多术语时,查询计划是所有循环连接。
是否有将查询提示应用于相交的语法?

使用 () () 尝试了两组 3 组,但这并没有改变查询计划。

  ( -- start term
      select [ftsIndexWordOnce].[sID] 
      from [ftsIndexWordOnce] with (nolock)
      where [ftsIndexWordOnce].[wordID] in ( 
             select [id] from [FTSwordDef] with (nolock) 
                                     where [word] like 'alpha')
  ) -- end term
INTERSECT
  ( -- start term
      select [ftsIndexWordOnce].[sID] 
      from [ftsIndexWordOnce] with (nolock)
      where [ftsIndexWordOnce].[wordID] in ( 
             select [id] from [FTSwordDef] with (nolock) 
                                     where [word] like 'beta')
  ) -- end term
INTERSECT
  ( -- start term
      select [ftsIndexWordOnce].[sID] 
      from [ftsIndexWordOnce] with (nolock)
      where [ftsIndexWordOnce].[wordID] in ( 
             select [id] from [FTSwordDef] with (nolock) 
                                     where [word] like 'gamma')
  ) -- end term
INTERSECT 
  ( -- start term
      select [ftsIndexWordOnce].[sID] 
      from [ftsIndexWordOnce] with (nolock)
      where [ftsIndexWordOnce].[wordID] in ( 
             select [id] from [FTSwordDef] with (nolock) 
                                     where [word] like 'delta')
  ) -- end term
INTERSECT
  ( -- start term
      select [ftsIndexWordOnce].[sID] 
      from [ftsIndexWordOnce] with (nolock)
      where [ftsIndexWordOnce].[wordID] in ( 
             select [id] from [FTSwordDef] with (nolock) 
                                     where [word] like 'epsilon')
  ) -- end term
INTERSECT
  ( -- start term
      select [ftsIndexWordOnce].[sID] 
      from [ftsIndexWordOnce] with (nolock)
      where [ftsIndexWordOnce].[wordID] in ( 
             select [id] from [FTSwordDef] with (nolock) 
                                     where [word] like 'phi')
  ) -- end term

认为我有一个修复

     select distinct [ftsIndexWordOnce].[sID] 
      from [ftsIndexWordOnce] with (nolock)
      Inner Merge Join [FTSwordDef] with (nolock) 
        On [FTSwordDef].[ID] = [ftsIndexWordOnce].[wordID] 
       And [FTSwordDef].[word] like 'alpha' 
  INTERSECT
     select distinct [ftsIndexWordOnce].[sID] 
      from [ftsIndexWordOnce] with (nolock)
      Inner Merge Join [FTSwordDef] with (nolock) 
        On [FTSwordDef].[ID] = [ftsIndexWordOnce].[wordID] 
       And [FTSwordDef].[word] like 'beta'

查询优化器在 5 或更多时仍然变得愚蠢,但这会强制第一个连接成为合并并保存它。

4

2 回答 2

1

可能想尝试“EXISTS”。“IN”可能会变得昂贵,尤其是对于大型列表。"EXISTS" 只查找第一个匹配项,而"IN" 试图找到所有匹配项。如果 sID 在 ftsIndexWordOnce 中是唯一的,那么下面的代码应该可以工作。如果没有,您可以在其上添加 distinct 或 group。

编辑:第一个脚本有逻辑错误。看评论。

SELECT
    [ftsIndexWordOnce].[sID]
FROM
    [ftsIndexWordOnce] WITH (NOLOCK)
WHERE
    EXISTS
    (
        SELECT
            NULL
        FROM
            [FTSwordDef] WITH (NOLOCK)
        WHERE
            [FTSwordDef].[word] LIKE 'alpha'
            AND
            [FTSwordDef].id = [ftsIndexWordOnce].wordid
    )
INTERSECT
SELECT
    [ftsIndexWordOnce].[sID]
FROM
    [ftsIndexWordOnce] WITH (NOLOCK)
WHERE
    EXISTS
    (
        SELECT
            NULL
        FROM
            [FTSwordDef] WITH (NOLOCK)
        WHERE
            [FTSwordDef].[word] LIKE 'beta'
            AND
            [FTSwordDef].id = [ftsIndexWordOnce].wordid
    )
INTERSECT
SELECT
    [ftsIndexWordOnce].[sID]
FROM
    [ftsIndexWordOnce] WITH (NOLOCK)
WHERE
    EXISTS
    (
        SELECT
            NULL
        FROM
            [FTSwordDef] WITH (NOLOCK)
        WHERE
            [FTSwordDef].[word] LIKE 'gamma'
            AND
            [FTSwordDef].id = [ftsIndexWordOnce].wordid
    )
INTERSECT
SELECT
    [ftsIndexWordOnce].[sID]
FROM
    [ftsIndexWordOnce] WITH (NOLOCK)
WHERE
    EXISTS
    (
        SELECT
            NULL
        FROM
            [FTSwordDef] WITH (NOLOCK)
        WHERE
            [FTSwordDef].[word] LIKE 'delta'
            AND
            [FTSwordDef].id = [ftsIndexWordOnce].wordid
    )
INTERSECT
SELECT
    [ftsIndexWordOnce].[sID]
FROM
    [ftsIndexWordOnce] WITH (NOLOCK)
WHERE
    EXISTS
    (
        SELECT
            NULL
        FROM
            [FTSwordDef] WITH (NOLOCK)
        WHERE
            [FTSwordDef].[word] LIKE 'epsilon'
            AND
            [FTSwordDef].id = [ftsIndexWordOnce].wordid
    )
INTERSECT
SELECT
    [ftsIndexWordOnce].[sID]
FROM
    [ftsIndexWordOnce] WITH (NOLOCK)
WHERE
    EXISTS
    (
        SELECT
            NULL
        FROM
            [FTSwordDef] WITH (NOLOCK)
        WHERE
            [FTSwordDef].[word] LIKE 'phi'
            AND
            [FTSwordDef].id = [ftsIndexWordOnce].wordid
    )
于 2013-06-10T15:46:47.063 回答
0

我遇到了和你非常相似的问题。

我想知道未定义数量的相交的共同值是什么。

由于性能损失,我无法使用动态 SQL。

所以我想出了一个模式如下:

WITH CTE AS (
    SELECT [FTSwordDef].[ID], -- Unique identifier of the referenced entity
           [ftsIndexWordOnce].[sID] -- The field that should be common for the intersect
    FROM [FTSwordDef]
    INNER JOIN [ftsIndexWordOnce]
        ON [FTSwordDef].[ID] = [ftsIndexWordOnce].[wordID]

    -- All your intersects becomes a query that returns all the participants of interest    
    WHERE [FTSwordDef].[word] IN ('alpha','beta','gamma','delta','epsilon','phi')   

    -- Optional GROUP BY if you don't trust the integrity of 
    -- your data and fear duplicate data may be present
    GROUP BY [FTSwordDef].[ID],[ftsIndexWordOnce].[sID]
)

SELECT [MAIN].[sID] -- The common value you wanted with the intersect
FROM CTE [MAIN]

-- We count the amount of participating entities (N Amount of intersect)
CROSS APPLY(
    SELECT COUNT(DISTINCT [A].[ID]) C FROM CTE [A]
) [A]

-- We count the occurrences of the common value
CROSS APPLY(
    SELECT COUNT([B].[sID]) C FROM CTE [B] WHERE [B].[sID] = [MAIN].[sID]
) [B]

-- If the value we want in common has equal occurrences as the amount of 
-- participating referenced entities, we can say the value is common for all
WHERE [A].[C] = [B].[C]
GROUP BY [MAIN].[sID]

这是一个小提琴http://sqlfiddle.com/#!18/2f1d9/55

于 2018-09-02T09:03:08.677 回答