【问题标题】:How to optimize the query which is taking too much time如何优化耗时过长的查询
【发布时间】:2017-06-01 17:21:15
【问题描述】:

在这个查询中,我在下面的查询中调用了一个函数“fnGetPoolWinner”2-3 次, 我认为这会减慢其性能或多个案例陈述是原因。

大约需要时间 00:01:39。

我尝试过在表中创建索引和创建公用表表达式然后使用该查询等选项,但没有找到任何解决方案来缩短时间。

DECLARE @TournamentId INT = 1

DECLARE @TournamentName AS NVARCHAR(MAX)

SELECT @TournamentName = TournamentName FROM Tournaments WHERE  TournamentId = @TournamentId


    SELECT 
    (SELECT CustomerIds FROM DBO.fnGetPoolWinner(SET_1.BracketBettingAmount,@TournamentId,
    (CASE
        WHEN SET_1.GAMES= 63
        THEN 1
        WHEN SET_1.GAMES= 31
        THEN 2
        WHEN SET_1.GAMES= 15
        THEN 3
        ELSE 0
    END))) AS [AccountNumber],
    @TournamentName AS TournamentName,
    (CASE
        WHEN SET_1.GAMES= 63
        THEN 'GENERAL POOL ROUND OF 64 $'+CAST(CAST(SET_1.BracketBettingAmount AS INT) AS NVARCHAR)+''
        WHEN SET_1.GAMES= 31
        THEN 'GENERAL POOL ROUND OF 32 $'+CAST(CAST(SET_1.BracketBettingAmount AS INT) AS NVARCHAR)+''
        WHEN SET_1.GAMES= 15
        THEN 'GENERAL POOL SWEET 16 $'+CAST(CAST(SET_1.BracketBettingAmount AS INT) AS NVARCHAR)+''
        ELSE ''
    END) AS [PoolName],
    (SELECT BracketNames FROM DBO.fnGetPoolWinner(SET_1.BracketBettingAmount,@TournamentId,
    (CASE
        WHEN SET_1.GAMES= 63
        THEN 1
        WHEN SET_1.GAMES= 31
        THEN 2
        WHEN SET_1.GAMES= 15
        THEN 3
        ELSE 0
    END))) AS GroupEntries,
    'Public' AS Access,
    COUNT(SET_1.BracketId) AS Members, 
    COUNT(SET_1.BracketId)*SET_1.BracketBettingAmount AS CurrentPoolPrize, 
    (SELECT WinnerNames FROM DBO.fnGetPoolWinner(SET_1.BracketBettingAmount,@TournamentId,
    (CASE
        WHEN SET_1.GAMES= 63
        THEN 1
        WHEN SET_1.GAMES= 31
        THEN 2
        WHEN SET_1.GAMES= 15
        THEN 3
        ELSE 0
    END))) AS WinnersName,
    (CASE
        WHEN SET_1.GAMES= 63
        THEN 1
        WHEN SET_1.GAMES= 31
        THEN 2
        WHEN SET_1.GAMES= 15
        THEN 3
        ELSE 0
    END) AS RoundId,
    SET_1.BracketBettingAmount AS BettingAmount
    FROM
        (SELECT BR.BracketId,
            BracketBettingAmount,
            (SELECT COUNT(1) FROM BracketPredictions AS BP WHERE BP.BracketPredictionBracketId =BR.BracketId) AS GAMES
        FROM Brackets AS BR WHERE BR.BracketTournamentId = @TournamentId AND BR.IsDeleted = 0) SET_1 WHERE SET_1.GAMES > 0
    GROUP BY SET_1.BracketBettingAmount, SET_1.GAMES HAVING SET_1.BracketBettingAmount IN (1,5,10,25)

【问题讨论】:

  • 检查 SSMS 中的查询执行计划,例如:建议您添加索引以获得更好的性能。
  • 有时我可以减少至少 300% 的查询执行时间,删除别名表达式、嵌套函数、直接在子查询中输入 where 子句等
  • @niksofteng,感谢您的建议。我已经检查了 SSMS 中的查询执行计划。而且我还在相关表中添加了索引。但遗憾的是没有得到任何结果。
  • 你的表值函数是内联的还是多语句的?尝试注释掉函数部分,看看是否能获得更好的性能。如果是这样,请在不使用该函数的情况下重写查询。
  • 我也打赌农场,如果你的功能问题。你能发布你的函数的代码吗?

标签: sql sql-server sql-server-2008 sql-server-performance


【解决方案1】:

试试这个,没测试过

DECLARE @TournamentId INT = 1

    with SET_1 as (

      SELECT BR.BracketId, BracketBettingAmount as BettingAmount, W.GAMES, TN.TournamentName,
             case W.GAMES 
             WHEN 63 THEN 1
             WHEN 31 THEN 2
             WHEN 15 THEN 3
             ELSE 0 END as IDGAME,

             CASE W.GAMES
             WHEN 63 THEN 'GENERAL POOL ROUND OF 64 $'+CAST(CAST(BracketBettingAmount AS INT) AS NVARCHAR)
             WHEN 31 THEN 'GENERAL POOL ROUND OF 32 $'+CAST(CAST(BracketBettingAmount AS INT) AS NVARCHAR)
             WHEN 15 THEN 'GENERAL POOL SWEET 16 $'   +CAST(CAST(BracketBettingAmount AS INT) AS NVARCHAR)
             ELSE '' END AS PoolName,

             TN.TournamentId

             FROM Brackets AS BR 
             cross apply
             (
                SELECT COUNT(*) GAMES FROM BracketPredictions AS BP WHERE BP.BracketPredictionBracketId =BR.BracketId
             ) W

             inner join Tournaments TN on BR.BracketTournamentId=TN.TournamentId

             WHERE BR.IsDeleted = 0 and BracketBettingAmount IN (1,5,10,25) and W.GAMES>0 and TN.TournamentId = @TournamentId


    ),

    NbBracketId as ( select NbBracketId, count(*) Nb from SET_1 group by NbBracketId) 


    SELECT 
    Y.CustomerIds AccountNumber, X.TournamentName, X.PoolName, Y.BracketNames AS GroupEntries, 'Public' AS Access,
    Z.NB AS Members, Z.NB*X.BettingAmount AS CurrentPoolPrize, Y.WinnerNames, X.IDGAME AS RoundId, X.BettingAmount
    FROM SET_1 X 
    outer apply DBO.fnGetPoolWinner(SET_1.BracketBettingAmount, SET_1.TournamentId, SET_1.IDGAME) as Y
    inner join NbBracketId Z on X.BracketId=Z.BracketId

【讨论】:

    【解决方案2】:

    DBO.fnGetPoolWinner 可以自行优化。

    试试这个方法,

    DECLARE @TournamentId INT = 1
    DECLARE @TournamentName AS NVARCHAR(MAX)
    SELECT @TournamentName = TournamentName FROM Tournaments WHERE  TournamentId = @TournamentId
    select @TournamentName TournamentName,
    CustomerIds AS [AccountNumber]
    ,(CASE
            WHEN SET_1.GAMES= 63
            THEN 'GENERAL POOL ROUND OF 64 $'+CAST(CAST(SET_1.BracketBettingAmount AS INT) AS NVARCHAR)+''
            WHEN SET_1.GAMES= 31
            THEN 'GENERAL POOL ROUND OF 32 $'+CAST(CAST(SET_1.BracketBettingAmount AS INT) AS NVARCHAR)+''
            WHEN SET_1.GAMES= 15
            THEN 'GENERAL POOL SWEET 16 $'+CAST(CAST(SET_1.BracketBettingAmount AS INT) AS NVARCHAR)+''
            ELSE ''
        END) AS [PoolName]
        ,ca.BracketNames as GroupEntries
         'Public' AS Access,
        COUNT(SET_1.BracketId) AS Members, 
        COUNT(SET_1.BracketId)*SET_1.BracketBettingAmount AS CurrentPoolPrize
        ,WinnerNames  as WinnersName
        , (CASE
            WHEN SET_1.GAMES= 63
            THEN 1
            WHEN SET_1.GAMES= 31
            THEN 2
            WHEN SET_1.GAMES= 15
            THEN 3
            ELSE 0
        END) AS RoundId,
        SET_1.BracketBettingAmount AS BettingAmount
     FROM
           (SELECT BR.BracketId,
                BracketBettingAmount,
                (SELECT COUNT(1) FROM BracketPredictions AS BP WHERE BP.BracketPredictionBracketId =BR.BracketId) AS GAMES
            FROM Brackets AS BR WHERE BR.BracketTournamentId = @TournamentId AND BR.IsDeleted = 0) SET_1 
            WHERE SET_1.GAMES > 0
        GROUP BY SET_1.BracketBettingAmount, SET_1.GAMES 
        HAVING SET_1.BracketBettingAmount IN (1,5,10,25)
    
        cross apply(SELECT CustomerIds,BracketNames,WinnerNames
         FROM DBO.fnGetPoolWinner(SET_1.BracketBettingAmount,@TournamentId,
        (CASE
            WHEN SET_1.GAMES= 63
            THEN 1
            WHEN SET_1.GAMES= 31
            THEN 2
            WHEN SET_1.GAMES= 15
            THEN 3
            ELSE 0
        END)) )ca
    

    【讨论】:

      猜你喜欢
      • 2018-10-06
      • 1970-01-01
      • 1970-01-01
      • 2023-02-14
      • 2019-08-02
      • 1970-01-01
      • 1970-01-01
      • 2011-11-03
      • 2015-10-23
      相关资源
      最近更新 更多