Sql 按案例联接的选择优于顺序联接的性能

Sql 按案例联接的选择优于顺序联接的性能,sql,sql-server,Sql,Sql Server,我已经为此绞尽脑汁了一段时间,在下面的一些情况下,sql需要30分钟才能在一个表上执行,该表的current中有100k行,大约有10行pending。这是一个更大的join语句的一部分,我已经确定它是罪魁祸首。基本上,sql的目的是对当前行和挂起行的副本的连接进行排序,以便所有挂起的行都位于顶部或底部。它是变革管理框架的一部分。你知道如何在一个始终表现良好的mannaer中做到这一点吗?对于记录,在某些情况下,相同的sql在10秒内运行在具有10万行和100个挂起更改的表上。排序是在计算字段上

我已经为此绞尽脑汁了一段时间,在下面的一些情况下,sql需要30分钟才能在一个表上执行,该表的
current
中有100k行,大约有10行
pending
。这是一个更大的join语句的一部分,我已经确定它是罪魁祸首。基本上,sql的目的是对
当前
行和
挂起
行的副本的连接进行排序,以便所有挂起的行都位于顶部或底部。它是变革管理框架的一部分。你知道如何在一个始终表现良好的mannaer中做到这一点吗?对于记录,在某些情况下,相同的sql在10秒内运行在具有10万行和100个挂起更改的表上。排序是在计算字段上进行的,这一事实使问题更加复杂。数据库是ms sql server 2008 R2

更新:我正在添加其余的连接,以显示疯狂中存在半理性

同样,此操作的唯一目的是获得当前记录和挂起记录的组合,以显示在更改得到批准、排序后,未来表的外观,以便在顶部或底部显示更改(HASPUNDING上的ASC或DSC),额外的Current2联接是为了添加一些额外的标识数据

一般来说,它会做它应该做的事情,相当不错的响应时间为几秒钟,当达到10米左右的记录时,响应时间为10秒。然而,在少数情况下,所有东西都会缓慢爬行,响应时间可达12-30分钟

WITH [ResultPage] AS 
SELECT 
    ROW_NUMBER() OVER 
    (ORDER BY 
        CASE WHEN [Current].[ID] IN 
            (SELECT [CID] 
             FROM [Pending] AS p
             INNER JOIN [Current] ON [Current].[ID] like p.[CID] 
             WHERE (p.[User] = 'admin'))
          THEN 1 
          ELSE 0 
       END ASC, 
       [Current].[ID] ASC) AS [RowID], 
    [Current].[ID], 
    CASE WHEN [Current].[ID] IN 
        (SELECT [CID] 
         FROM [Pending] AS p 
     INNER JOIN [Current]  ON [Current].[ID] like p.[CID] 
         WHERE (p.[User] = 'admin'))
       THEN 1 
       ELSE 0 
    END AS [HasPending] 
FROM [Current] 
INNER JOIN [Current2] AS [Table2] ON ([Current].[T2ID] = [Table2].[ID])
SELECT [ResultPage].[RowID], [ResultPage].[HasPending], [Current2].[ID] As [Current2^ID], [Tag].Name], 
etc... etc...
FROM [ResultPage] 
INNER JOIN [Current]  ON ([Current].[ID] = [ResultPage].[ID]) 
 INNER JOIN [Current2] ON ([Current].[T2ID] = [Current2].[ID]) 
 WHERE (([ResultPage].[RowID] BETWEEN -1 AND 50)) ORDER BY [ResultPage].[RowID] ASC

尝试一下,这应该会加快速度,因为ID将转储到表变量中,而不必在每个循环中查询。这很可能不是最好的解决方案,但如果没有关于您正在尝试做什么的进一步信息,这至少会有所帮助

declare @ids table
(
    id int
)

insert into @ids(id)
SELECT [ID] From [Pending]
Inner Join [Current] On [Current].[ID] = [Pending].[ID] 
WHERE ([Pending].[User] = 'admin')

SELECT ROW_NUMBER() OVER 
    (ORDER BY Case When [Current].[ID] In (select id from @ids) 
    THEN 1 ELSE 0 END ASC, [Current].[ID] ASC) As [RowID], 
    [Current].[ID], 
    Case When [Current].[ID] In (select id from @ids)
    THEN 1 ELSE 0 END AS [HasPending] 
FROM [Current] 
INNER JOIN [Current2] AS [Table2] ON ([Current].[T2ID] = [Table2].[ID])
如果您的ID是唯一的,您也可以使用此选项,我假定它们是:

SELECT ROW_NUMBER() OVER 
    (ORDER BY a.haspending, a.[ID] ASC) As [RowID],
    a.id, a.haspending,
from (select [Current].[ID], 
      Case when a.id is not null THEN 1 ELSE 0 END [HasPending] 
        FROM [Current] 
        INNER JOIN [Current2] AS [Table2] ON ([Current].[T2ID] = [Table2].[ID])
        left join  (SELECT distinct [ID] From [Pending]
                    Inner Join [Current] On [Current].[ID] = [Pending].[ID] 
                    WHERE ([Pending].[User] = 'admin')) a on a.id = [Current].[ID]) a

尝试一下,这应该会加快速度,因为ID将转储到表变量中,而不必在每个循环中查询。这很可能不是最好的解决方案,但如果没有关于您正在尝试做什么的进一步信息,这至少会有所帮助

declare @ids table
(
    id int
)

insert into @ids(id)
SELECT [ID] From [Pending]
Inner Join [Current] On [Current].[ID] = [Pending].[ID] 
WHERE ([Pending].[User] = 'admin')

SELECT ROW_NUMBER() OVER 
    (ORDER BY Case When [Current].[ID] In (select id from @ids) 
    THEN 1 ELSE 0 END ASC, [Current].[ID] ASC) As [RowID], 
    [Current].[ID], 
    Case When [Current].[ID] In (select id from @ids)
    THEN 1 ELSE 0 END AS [HasPending] 
FROM [Current] 
INNER JOIN [Current2] AS [Table2] ON ([Current].[T2ID] = [Table2].[ID])
如果您的ID是唯一的,您也可以使用此选项,我假定它们是:

SELECT ROW_NUMBER() OVER 
    (ORDER BY a.haspending, a.[ID] ASC) As [RowID],
    a.id, a.haspending,
from (select [Current].[ID], 
      Case when a.id is not null THEN 1 ELSE 0 END [HasPending] 
        FROM [Current] 
        INNER JOIN [Current2] AS [Table2] ON ([Current].[T2ID] = [Table2].[ID])
        left join  (SELECT distinct [ID] From [Pending]
                    Inner Join [Current] On [Current].[ID] = [Pending].[ID] 
                    WHERE ([Pending].[User] = 'admin')) a on a.id = [Current].[ID]) a

我想拥有一个双重子查询是相当昂贵的。如果您在单个子查询中确定
[hasPending]
,并保存在一些
连接上,它的性能可能会更好

SELECT
    [sub].[ID],
    ROW_NUMBER() OVER (ORDER BY [sub].[hasPending] DESC, [sub].[ID] ASC) AS [RowID],
    [sub].[hasPending]
FROM
(
    SELECT
        [Current].[ID],
        (CASE WHEN COUNT([pending].[ID]) > 0 THEN 1 ELSE 0 END) AS [hasPending]
    FROM [Current]
    INNER JOIN [Current2] 
        ON [Current].[T2ID] = [Current2].[ID]
    LEFT JOIN [Pending] 
        ON [Current].[ID] = [Pending].[ID] AND [Pending].[User] = 'Admin'
    GROUP BY [Current].[ID]
) AS [sub]

编辑:将
COUNT(*)
更改为
COUNT([pending].[ID])
,以便正确地确定
[hasPending]

我想拥有一个双重子查询是相当昂贵的。如果您在单个子查询中确定
[hasPending]
,并保存在一些
连接上,它的性能可能会更好

SELECT
    [sub].[ID],
    ROW_NUMBER() OVER (ORDER BY [sub].[hasPending] DESC, [sub].[ID] ASC) AS [RowID],
    [sub].[hasPending]
FROM
(
    SELECT
        [Current].[ID],
        (CASE WHEN COUNT([pending].[ID]) > 0 THEN 1 ELSE 0 END) AS [hasPending]
    FROM [Current]
    INNER JOIN [Current2] 
        ON [Current].[T2ID] = [Current2].[ID]
    LEFT JOIN [Pending] 
        ON [Current].[ID] = [Pending].[ID] AND [Pending].[User] = 'Admin'
    GROUP BY [Current].[ID]
) AS [sub]

编辑:将
COUNT(*)
更改为
COUNT([pending].[ID])
,以便正确地确定
[hasinding]

好的,在Jacco建议的帮助下,修改它以得到我想要的正确结果,我能够运行它,将查询减少到惊人的1秒

WITH [ResultPage] AS 
(SELECT
    sub.id as id,
    ROW_NUMBER() OVER (ORDER BY [sub].[hasPending] DESC, [sub].[ID] ASC) AS [RowID],
    [sub].[hasPending]
 FROM
(
SELECT
    a.[ID],
    (CASE WHEN p.[CID] is not null THEN 1 ELSE 0 END) AS [hasPending]
FROM [Alarm] a

full outer JOIN [Pending] as p
    ON a.[ID] like p.[CID] 
GROUP BY a.[ID],p.[CID]
) AS [sub]
INNER JOIN [Current2] ON (sub.[T2ID] = [Current2].[ID]))
SELECT [ResultPage].[RowID], [ResultPage].[HasPending], [Current2].[ID] As [Current2^ID],
etc...etc...
 FROM [ResultPage] 
INNER JOIN [Current] ON ([Current].[ID] = [ResultPage].[ID]) 
INNER JOIN [Current2] ON ([Current].[T2ID] = [Current2].[ID]) 
WHERE (([ResultPage].[RowID] BETWEEN -1 AND 50)) ORDER BY [ResultPage].[RowID] ASC

好的,在Jacco的建议的帮助下,我修改了它以得到我想要的正确结果,我能够让它运行,将查询时间缩短到惊人的1秒

WITH [ResultPage] AS 
(SELECT
    sub.id as id,
    ROW_NUMBER() OVER (ORDER BY [sub].[hasPending] DESC, [sub].[ID] ASC) AS [RowID],
    [sub].[hasPending]
 FROM
(
SELECT
    a.[ID],
    (CASE WHEN p.[CID] is not null THEN 1 ELSE 0 END) AS [hasPending]
FROM [Alarm] a

full outer JOIN [Pending] as p
    ON a.[ID] like p.[CID] 
GROUP BY a.[ID],p.[CID]
) AS [sub]
INNER JOIN [Current2] ON (sub.[T2ID] = [Current2].[ID]))
SELECT [ResultPage].[RowID], [ResultPage].[HasPending], [Current2].[ID] As [Current2^ID],
etc...etc...
 FROM [ResultPage] 
INNER JOIN [Current] ON ([Current].[ID] = [ResultPage].[ID]) 
INNER JOIN [Current2] ON ([Current].[T2ID] = [Current2].[ID]) 
WHERE (([ResultPage].[RowID] BETWEEN -1 AND 50)) ORDER BY [ResultPage].[RowID] ASC


对不起,这看起来很精神。你能解释一下它试图实现什么吗?是的,这看起来是错误的,非常错误。我会将该查询的结果具体化到一个临时表中,然后连接到临时表。很抱歉,这看起来是心理问题。你能解释一下它试图达到什么目的吗?是的,这看起来是错误的,所以是错误的。我会将该查询的结果具体化到一个临时表中,然后连接到临时表。当前到当前2表的连接可能是一对多的,你会删除行,因此如果是这样的话,这可能是不对的。如果admin和其他人是有问题的用户,那么您将在join中得到2行。一个有未决的,一个没有未决的。没关系,我错了。它基本上与我编写的第二个查询相同,只是稍微不那么复杂。谢谢,我尝试使用我的数据运行该查询,并且haspending在每一行上都是真的,尽管应该只有8行。结果表明它需要一个完整的外部联接,而不是左联接,然后可以通过检查id字段是否为null来确定HasPending,这可能也是错误的。您需要的是将(COUNT(*)>0时的CASE,然后是1 ELSE 0 END)更改为(pending.id不为null时的CASE,然后是1 ELSE 0 END)因为计数总是会大于0,因为唯一不大于0的方法是如果该行没有返回。当前到current2表的联接可能是一对多的联接,您将删除行,因此如果是这种情况,这可能不正确。如果admin和其他人是有问题的用户,那么您将在join中得到2行。一个有未决的,一个没有未决的。没关系,我错了。它基本上与我编写的第二个查询相同,只是稍微不那么复杂。谢谢,我尝试使用我的数据运行该查询,并且haspending在每一行上都是真的,尽管应该只有8行。结果表明它需要一个完整的外部联接,而不是左联接,然后可以通过检查id字段是否为null来确定HasPending,这可能也是错误的。您需要将(CASE WHEN COUNT(*)>0,然后1 ELSE 0 END)更改为(CASE WHEN pending.id不为null,然后1 ELSE 0 END),因为计数总是大于0,因为唯一不大于0的方法是如果行没有返回。谢谢,无论我如何扭曲,sql管理器都不会接受此代码,我尝试删除,before from(选择,但是它仍然抱怨最后一个)谢谢,无论我如何扭曲它,sql manager都不会接受此代码,我尝试删除before from(选择,但是它仍然抱怨最后一个)