全面优化多个Interset

问题描述 投票:0回答:2

问题查询使用多个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个或更多个术语中,查询计划是所有循环连接。 是否有将查询提示应用于Intersect的语法?

尝试了两组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或更多时愚蠢,但这会强制第一个连接成为合并并保存它。

sql-server-2008 tsql intersect query-hints
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
    )

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

© www.soinside.com 2019 - 2024. All rights reserved.