【问题标题】:Improve TSQL Stored Procedure for pairwise execution of procedure改进 SQL 存储过程以成对执行过程
【发布时间】:2014-06-02 05:42:24
【问题描述】:

更新: 我将第一部分重写为基于集合的方法:

declare @AllRunnersString nvarchar(200) ='2342;1228;1075;266;423;2849;1690;488;162;1153;1666'
DECLARE @pairs table
(p1 int,p2 int) 
insert into @pairs(p1, p2)
select sp1.value as p1, sp2.value as p2
from dbo.split(';', @AllRunnersString) sp1
inner join dbo.split(';', @AllRunnersString) sp2
on sp1.value <> sp2.value

这会生成对。

Head2Head 获取 id 并返回一个包含两个 id 的所有事件的表。 @rtn 表( eventid int, p1 整数, p2 整数, ldiff 浮动, pdiff 浮动, 赢家诠释 )

我需要获取所有这些事件并将它们存储在一个表格中,用于来自@pairs 的所有组合。

使用基于过程的方法,我会在@pairs 上运行光标,并使用过程计算每对的值并插入到最终表中。

也许这部分有一个基于集合的方法..

【问题讨论】:

  • 您是否考虑过以应有的方式编写 SQL,即作为基于 SET 的操作?您基本上是在面向集合的环境中编写程序代码。
  • 是的,你是对的,我已经修改了代码。尽管如此,使用基于集合的逻辑执行某些编码“操作”比其他操作更难

标签: sql-server performance tsql stored-procedures


【解决方案1】:

你的描述很好理解,如果你的函数getHead2Head的文本也可用的话还是很好的。同时提供一些数据来证明你的问题。

我看了你的介绍,我有一些建议

  1. 为什么要使用 2 循环,而不是使用 1 循环。

  2. 在这种情况下最好使用光标代替 while ,您可以更好地控制它,最后没有设置更新用于重置。

快速查询的主要问题与您的每个查询和每个 where 条件相关。

您可以为临时表提供主键,这将获得快速的结果。(创建主键与普通表一样简单)

Creating a Primary Key on a temp table - When?

【讨论】:

    【解决方案2】:

    您尝试在 TSQL 中重建真正的数据库任务 - 构建循环以匹配记录。不要使用程序代码,使用集合代码并让服务器执行循环和其他操作。他会做得更好,没有冒犯。例如,如果您想随机加入只有一对合作伙伴/候选人对的合作伙伴,您可以执行以下操作:

    WITH player_combination
    AS (
        --Cross Joins selects all combinations of mutually different players
        SELECT p.playerid [partner], c.playerid candidate,newid() random_id
        FROM @playerid p, @playerid c
        WHERE p.playerid<>c.playerid
    )
    SELECT pc.[partner],pc.candidate
    FROM player_combination pc
        JOIN (SELECT [partner], max(random_id) random_id --Select the record with max random_id
                FROM player_combination
                GROUP BY [partner]) tmp ON tmp.[partner]=pc.[partner] AND tmp.random_id=pc.random_id
    

    如果您可以选择免费玩家的最大 id,那么声明就更简单了:

    WITH player_combination
    AS (
        --Cross Joins selects all combinations of mutually different players
        SELECT p.playerid [partner], c.playerid candidate
        FROM @playerid p, @playerid c
        WHERE p.playerid<>c.playerid
    )
    SELECT pc.[partner],pc.candidate
    FROM player_combination pc
        JOIN (SELECT [partner], max(candidate) candidate --Select the record with max candidate id
                FROM player_combination
                GROUP BY [partner]) tmp ON tmp.[partner]=pc.[partner] AND tmp.random_id=pc.random_id
    

    我很确定你也可以摆脱 getHead2Head 函数。

    【讨论】:

    • 谢谢。我相信这会负责生成合作伙伴-候选人组合。 Head2Head 返回一对事件表,该表又是合作伙伴和候选人的 2 个共享属性之间的差异。
    【解决方案3】:

    最好切换到使用表值参数或 XML 传递参数,这自然支持多个值而不是将它们塞进字符串中,但既然你已经有了那个部分并且它对你“工作” ,我们就不用管它了。

    以下应该是等价的:

    declare @AllRunnersString nvarchar(200)   
        ='2342;1228;1075;266;423;2849;1690;488;162;1153;1666'
    
    declare @rtn table
    (
       eventid int,
       player1 int,
       player2 int,
       lengthdiff float,
       placediff float,
       winner int
    )
    
    declare @playerids table
    (
        playerid int
    )
    
    -- parse string into table
    insert into @playerids(playerid)
       select value 
       from split(';', @AllRunnersString) 
    
    insert into @rtn(eventid, player1, player2, lengthdiff, placediff, winner)
    select eventid, player1, player2, lengthdiff, placediff, winner 
    from
     @playerids p1
       inner join
     @playerids p2
       on
         p1.playerid != p2.playerid
       cross apply
        getHead2Head(p1.playerid, p2.playerid, 3)
    

    如果我们可以消除对getHead2Head 的调用并将其内容直接包含在此查询中,则可能还有进一步改进此功能的机会。

    【讨论】:

    • 谢谢!! - 交叉应用是我有限的 SQL 词汇中缺少的东西!我使用示例字符串运行查询,它花费了
    猜你喜欢
    • 2011-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-15
    相关资源
    最近更新 更多